licensed 4.0.4 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -1
- data/Gemfile.lock +1 -1
- data/docs/configuration/README.md +1 -0
- data/docs/configuration/additional_terms.md +41 -0
- data/docs/configuration/ignoring_dependencies.md +13 -0
- data/docs/configuration/reviewing_dependencies.md +13 -0
- data/docs/configuration.md +7 -0
- data/docs/sources/pnpm.md +20 -0
- data/lib/licensed/commands/cache.rb +3 -3
- data/lib/licensed/commands/status.rb +5 -4
- data/lib/licensed/configuration.rb +48 -12
- data/lib/licensed/dependency.rb +40 -8
- data/lib/licensed/sources/gradle.rb +62 -60
- data/lib/licensed/sources/pnpm.rb +58 -0
- data/lib/licensed/sources/source.rb +15 -2
- data/lib/licensed/sources.rb +4 -3
- data/lib/licensed/version.rb +1 -1
- metadata +5 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 2b65e198a420b03486b2680a6a83fb04b4e67684d28bc4ba9ef00c466ffd7489
         | 
| 4 | 
            +
              data.tar.gz: ab2b10c6e854d3f1d7faa918e48addb497032838fd1cea942ff823053b891150
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 8dee38c45e73cb03b7c94a9260bb9bc6f5919f53156b69a751238693920e2f120a3dcb0d43f66270fa9abc8305705fdced290978e51bfe762be5f0e5ba00230d
         | 
| 7 | 
            +
              data.tar.gz: d352b46e40f545f0bd3e1aa29e3bb62454e2e329c64ce9197ba1f9c38b4f11bcbbbecc789658dcff0e6b79e43b4ee9cc839b5476e23cab44a559a605ddbd77b6
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -6,6 +6,23 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. | |
| 6 6 |  | 
| 7 7 | 
             
            ## [Unreleased]
         | 
| 8 8 |  | 
| 9 | 
            +
            ## 4.2.0
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            ### Added
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            - Reviewed and ignored configuration lists support matching on versions and version ranges (https://github.com/github/licensed/pull/629)
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            ### Fixed
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            - Licensed should more reliably source dependencies from Gradle >= 8.0 (https://github.com/github/licensed/pull/630)
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            ## 4.1.0
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            ### Added
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            - Custom license terms can be added to dependencies via new configuration options (https://github.com/github/licensed/pull/624)
         | 
| 24 | 
            +
            - Licensed is now integrated with pnpm to enumerate dependencies (https://github.com/github/licensed/pull/626)
         | 
| 25 | 
            +
             | 
| 9 26 | 
             
            ## 4.0.4
         | 
| 10 27 |  | 
| 11 28 | 
             
            ### Changed
         | 
| @@ -706,4 +723,4 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. | |
| 706 723 |  | 
| 707 724 | 
             
            Initial release :tada:
         | 
| 708 725 |  | 
| 709 | 
            -
            [Unreleased]: https://github.com/github/licensed/compare/4.0 | 
| 726 | 
            +
            [Unreleased]: https://github.com/github/licensed/compare/4.2.0...HEAD
         | 
    
        data/Gemfile.lock
    CHANGED
    
    
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            # Additional terms
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            The `additional_terms` configuration option is used to specify paths to files containing extra licensing terms that do not ship with the dependency package. All files specified are expected to be plain text.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Files containing additional content can be located anywhere on disk that is accessible to licensed.  File paths can be specified as a string or array and can contain glob values to simplify configuration inputs.  All file paths are evaluated from the [configuration root](./configuration_root.md).
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            ## Examples
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            **Note** The examples below specify paths to additional files under the `.licenses` folder.  This is a logical place to store files containing license terms, but be careful not to store files under paths managed by licensed like `.licenses/<source type>/...`.  Running `licensed cache` in the future will delete any files under licensed managed paths that licensed did not create.  This is why the below examples use paths like `.licenses/amendments/bundler/...` instead of not `.licenses/bundler/amendments/...`.
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            ### With a string
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            ```yaml
         | 
| 14 | 
            +
            additional_terms:
         | 
| 15 | 
            +
              # specify the type of dependency
         | 
| 16 | 
            +
              bundler:
         | 
| 17 | 
            +
                # specify the dependency name and path to an additional file
         | 
| 18 | 
            +
                <gem-name>: .licenses/amendments/bundler/<gem-name>/terms.txt
         | 
| 19 | 
            +
            ```
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            ### With a glob string
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            ```yaml
         | 
| 24 | 
            +
            additional_terms:
         | 
| 25 | 
            +
              # specify the type of dependency
         | 
| 26 | 
            +
              bundler:
         | 
| 27 | 
            +
                # specify the dependency name and one or more additional files with a glob pattern
         | 
| 28 | 
            +
                <gem-name>: .licenses/amendments/bundler/<gem-name>/*.txt
         | 
| 29 | 
            +
            ```
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            ### With an array of strings
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            ```yaml
         | 
| 34 | 
            +
            additional_terms:
         | 
| 35 | 
            +
              # specify the type of dependency
         | 
| 36 | 
            +
              bundler:
         | 
| 37 | 
            +
                # specify the dependency name and array of paths to additional files
         | 
| 38 | 
            +
                <gem-name>:
         | 
| 39 | 
            +
                  - .licenses/amendments/bundler/<gem-name>/terms-1.txt
         | 
| 40 | 
            +
                  - .licenses/amendments/bundler/<gem-name>/terms-2.txt
         | 
| 41 | 
            +
            ```
         | 
| @@ -17,3 +17,16 @@ ignored: | |
| 17 17 | 
             
              go:
         | 
| 18 18 | 
             
                - github.com/me/my-repo/**/*
         | 
| 19 19 | 
             
            ```
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            ## Ignoring dependencies at specific versions
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            Ignore a dependency at specific versions by appending `@<version>` to the end of the dependency's name in an `ignore` list.  If a dependency is configured to be ignored at a specific version, licensed will not ignore non-matching versions of the dependency.
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            The version value can be one of:
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            1. `"*"` - match any version value
         | 
| 28 | 
            +
            1. any version string, or version range string, that can be parsed by `Gem::Requirement`
         | 
| 29 | 
            +
               - a semantic version - `dependency@1.2.3`
         | 
| 30 | 
            +
               - a gem requirement range - `dependency@~> 1.0.0` or `dependency@< 3.0`
         | 
| 31 | 
            +
               - see the [Rubygems version guides](https://guides.rubygems.org/patterns/#pessimistic-version-constraint) for more details about specifying gem version requirements
         | 
| 32 | 
            +
            1. a value that can't be parsed by `Gem::Requirement`, which will only match dependencies with the same version string
         | 
| @@ -16,3 +16,16 @@ reviewed: | |
| 16 16 | 
             
              bundler:
         | 
| 17 17 | 
             
                - gem-using-unallowed-license
         | 
| 18 18 | 
             
            ```
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            ## Reviewing dependencies at specific versions
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            Review a dependency at specific versions by appending `@<version>` to the end of the dependency's name in an `reviewed` list.  If a dependency is configured to be reviewed at a specific version, licensed will not recognize non-matching versions of the dependency as being manually reviewed and accepted.
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            The version value can be one of:
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            1. `"*"` - match any version value
         | 
| 27 | 
            +
            1. any version string, or version range string, that can be parsed by `Gem::Requirement`
         | 
| 28 | 
            +
               - a semantic version - `dependency@1.2.3`
         | 
| 29 | 
            +
               - a gem requirement range - `dependency@~> 1.0.0` or `dependency@< 3.0`
         | 
| 30 | 
            +
               - see the [Rubygems version guides](https://guides.rubygems.org/patterns/#pessimistic-version-constraint) for more details about specifying gem version requirements
         | 
| 31 | 
            +
            1. a value that can't be parsed by `Gem::Requirement`, which will only match dependencies with the same version string
         | 
    
        data/docs/configuration.md
    CHANGED
    
    | @@ -67,6 +67,13 @@ reviewed: | |
| 67 67 | 
             
              - classlist # public domain
         | 
| 68 68 | 
             
              - octicons
         | 
| 69 69 |  | 
| 70 | 
            +
            # Specify additional license terms that have been obtained from a dependency's owner
         | 
| 71 | 
            +
            # which apply to the dependency's license 
         | 
| 72 | 
            +
            additional_terms:
         | 
| 73 | 
            +
              bundler:
         | 
| 74 | 
            +
                bcrypt-ruby:
         | 
| 75 | 
            +
                  - .licenses/amendments/bundler/bcrypt-ruby/amendment.txt
         | 
| 76 | 
            +
             | 
| 70 77 | 
             
            # A single configuration file can be used to enumerate dependencies for multiple
         | 
| 71 78 | 
             
            # projects.  Each configuration is referred to as an "application" and must include
         | 
| 72 79 | 
             
            # a source path, at a minimum
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            # pnpm
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            The npm source will detect dependencies when `pnpm-lock.yaml` is found at an apps `source_path`.  It uses `pnpm licenses list` to enumerate dependencies and metadata.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            All dependencies enumerated by the pnpm source include the dependency version in the dependency's name identifier.  All [reviewed](../configuration/reviewing_dependencies.md) or [ignored](../configuration/ignoring_dependencies.md) dependencies must include a version signifier in the configured dependency name.
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            **NOTE** [pnpm licenses list](https://pnpm.io/cli/licenses) is an experimental CLI command and subject to change.  If changes to pnpm result in unexpected or broken behavior in licensed please open an [issue](https://github.com/github/licensed/issues/new).
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ## Including development dependencies
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            By default, the npm source will exclude all development dependencies. To include development or test dependencies, set `production_only: false` in the licensed configuration.
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            ```yml
         | 
| 14 | 
            +
            pnpm:
         | 
| 15 | 
            +
              production_only: false
         | 
| 16 | 
            +
            ```
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            ## Using licensed with pnpm workspaces
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            Licensed will locate all dependencies from all pnpm workspaces and cannot enumerate dependencies from individual project workspaces.  This is a limitation from the pnpm CLI.
         | 
| @@ -83,7 +83,7 @@ module Licensed | |
| 83 83 | 
             
                    report["version"] = dependency.version
         | 
| 84 84 |  | 
| 85 85 | 
             
                    if save_dependency_record?(dependency, cached_record)
         | 
| 86 | 
            -
                      update_dependency_from_cached_record(app, dependency, cached_record)
         | 
| 86 | 
            +
                      update_dependency_from_cached_record(app, source, dependency, cached_record)
         | 
| 87 87 |  | 
| 88 88 | 
             
                      dependency.record.save(filename)
         | 
| 89 89 | 
             
                      report["cached"] = true
         | 
| @@ -123,14 +123,14 @@ module Licensed | |
| 123 123 | 
             
                  # Update dependency metadata from the cached record, to support:
         | 
| 124 124 | 
             
                  # 1. continuity between cache runs to cut down on churn
         | 
| 125 125 | 
             
                  # 2. notifying users when changed content needs to be reviewed
         | 
| 126 | 
            -
                  def update_dependency_from_cached_record(app, dependency, cached_record)
         | 
| 126 | 
            +
                  def update_dependency_from_cached_record(app, source, dependency, cached_record)
         | 
| 127 127 | 
             
                    return if cached_record.nil?
         | 
| 128 128 | 
             
                    return if options[:force]
         | 
| 129 129 |  | 
| 130 130 | 
             
                    if dependency.record.matches?(cached_record)
         | 
| 131 131 | 
             
                      # use the cached license value if the license text wasn't updated
         | 
| 132 132 | 
             
                      dependency.record["license"] = cached_record["license"]
         | 
| 133 | 
            -
                    elsif app.reviewed?(dependency.record)
         | 
| 133 | 
            +
                    elsif app.reviewed?(dependency.record, require_version: source.class.require_matched_dependency_version)
         | 
| 134 134 | 
             
                      # if the license text changed and the dependency is set as reviewed
         | 
| 135 135 | 
             
                      # force a re-review of the dependency
         | 
| 136 136 | 
             
                      dependency.record["review_changed_license"] = true
         | 
| @@ -60,7 +60,7 @@ module Licensed | |
| 60 60 | 
             
                      report.errors << "missing license text" if record.licenses.empty?
         | 
| 61 61 | 
             
                      if record["review_changed_license"]
         | 
| 62 62 | 
             
                        report.errors << "license text has changed and needs re-review. if the new text is ok, remove the `review_changed_license` flag from the cached record"
         | 
| 63 | 
            -
                      elsif license_needs_review?(app, record)
         | 
| 63 | 
            +
                      elsif license_needs_review?(app, source, record)
         | 
| 64 64 | 
             
                        report.errors << needs_review_error_message(app, record)
         | 
| 65 65 | 
             
                      end
         | 
| 66 66 | 
             
                    end
         | 
| @@ -70,9 +70,10 @@ module Licensed | |
| 70 70 |  | 
| 71 71 | 
             
                  # Returns true if a cached record needs further review based on the
         | 
| 72 72 | 
             
                  # record's license(s) and the app's configuration
         | 
| 73 | 
            -
                  def license_needs_review?(app, record)
         | 
| 73 | 
            +
                  def license_needs_review?(app, source, record)
         | 
| 74 74 | 
             
                    # review is not needed if the record is set as reviewed
         | 
| 75 | 
            -
                     | 
| 75 | 
            +
                    require_version = data_source == "configuration" || source.class.require_matched_dependency_version
         | 
| 76 | 
            +
                    return false if app.reviewed?(record, require_version: require_version)
         | 
| 76 77 |  | 
| 77 78 | 
             
                    # review is not needed if the top level license is allowed
         | 
| 78 79 | 
             
                    return false if app.allowed?(record["license"])
         | 
| @@ -99,7 +100,7 @@ module Licensed | |
| 99 100 | 
             
                    error = "dependency needs review"
         | 
| 100 101 |  | 
| 101 102 | 
             
                    # look for an unversioned reviewed list match
         | 
| 102 | 
            -
                    if app.reviewed?(record,  | 
| 103 | 
            +
                    if app.reviewed?(record, require_version: false)
         | 
| 103 104 | 
             
                      error += ", unversioned 'reviewed' match found: #{record["name"]}"
         | 
| 104 105 | 
             
                    end
         | 
| 105 106 |  | 
| @@ -10,6 +10,8 @@ module Licensed | |
| 10 10 |  | 
| 11 11 | 
             
                DEFAULT_CACHE_PATH = ".licenses".freeze
         | 
| 12 12 |  | 
| 13 | 
            +
                ANY_VERSION_REQUIREMENT = "*".freeze
         | 
| 14 | 
            +
             | 
| 13 15 | 
             
                # Returns the root for a configuration in following order of precedence:
         | 
| 14 16 | 
             
                # 1. explicitly configured "root" property
         | 
| 15 17 | 
             
                # 2. a found git repository root
         | 
| @@ -73,8 +75,8 @@ module Licensed | |
| 73 75 | 
             
                end
         | 
| 74 76 |  | 
| 75 77 | 
             
                # Is the given dependency reviewed?
         | 
| 76 | 
            -
                def reviewed?(dependency,  | 
| 77 | 
            -
                  any_list_pattern_matched? self["reviewed"][dependency["type"]], dependency,  | 
| 78 | 
            +
                def reviewed?(dependency, require_version: false)
         | 
| 79 | 
            +
                  any_list_pattern_matched? self["reviewed"][dependency["type"]], dependency, require_version: require_version
         | 
| 78 80 | 
             
                end
         | 
| 79 81 |  | 
| 80 82 | 
             
                # Find all reviewed dependencies that match the provided dependency's name
         | 
| @@ -83,8 +85,8 @@ module Licensed | |
| 83 85 | 
             
                end
         | 
| 84 86 |  | 
| 85 87 | 
             
                # Is the given dependency ignored?
         | 
| 86 | 
            -
                def ignored?(dependency)
         | 
| 87 | 
            -
                  any_list_pattern_matched? self["ignored"][dependency["type"]], dependency
         | 
| 88 | 
            +
                def ignored?(dependency, require_version: false)
         | 
| 89 | 
            +
                  any_list_pattern_matched? self["ignored"][dependency["type"]], dependency, require_version: require_version
         | 
| 88 90 | 
             
                end
         | 
| 89 91 |  | 
| 90 92 | 
             
                # Is the license of the dependency allowed?
         | 
| @@ -93,8 +95,10 @@ module Licensed | |
| 93 95 | 
             
                end
         | 
| 94 96 |  | 
| 95 97 | 
             
                # Ignore a dependency
         | 
| 96 | 
            -
                def ignore(dependency)
         | 
| 97 | 
            -
                   | 
| 98 | 
            +
                def ignore(dependency, at_version: false)
         | 
| 99 | 
            +
                  id = dependency["name"]
         | 
| 100 | 
            +
                  id += "@#{dependency["version"]}" if at_version && dependency["version"]
         | 
| 101 | 
            +
                  (self["ignored"][dependency["type"]] ||= []) << id
         | 
| 98 102 | 
             
                end
         | 
| 99 103 |  | 
| 100 104 | 
             
                # Set a dependency as reviewed
         | 
| @@ -109,17 +113,49 @@ module Licensed | |
| 109 113 | 
             
                  self["allowed"] << license
         | 
| 110 114 | 
             
                end
         | 
| 111 115 |  | 
| 116 | 
            +
                # Returns an array of paths to files containing additional license terms.
         | 
| 117 | 
            +
                def additional_terms_for_dependency(dependency)
         | 
| 118 | 
            +
                  amendment_paths = Array(self.dig("additional_terms", dependency["type"], dependency["name"]))
         | 
| 119 | 
            +
                  amendment_paths.flat_map { |path| Dir.glob(self.root.join(path)) }
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
             | 
| 112 122 | 
             
                private
         | 
| 113 123 |  | 
| 114 | 
            -
                def any_list_pattern_matched?(list, dependency,  | 
| 124 | 
            +
                def any_list_pattern_matched?(list, dependency, require_version: false)
         | 
| 115 125 | 
             
                  Array(list).any? do |pattern|
         | 
| 116 | 
            -
                     | 
| 117 | 
            -
             | 
| 118 | 
            -
             | 
| 119 | 
            -
             | 
| 126 | 
            +
                    # parse a name and version requirement value from the pattern
         | 
| 127 | 
            +
                    name, requirement = pattern.rpartition("@").values_at(0, 2).map(&:strip)
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                    if name == ""
         | 
| 130 | 
            +
                      # if name == "", then the pattern doesn't contain a valid version value.
         | 
| 131 | 
            +
                      # treat the entire pattern as the dependency name with no version.
         | 
| 132 | 
            +
                      name = pattern
         | 
| 133 | 
            +
                      requirement = nil
         | 
| 134 | 
            +
                    elsif !requirement.to_s.empty?
         | 
| 135 | 
            +
                      # check if the version requirement is a valid Gem::Requirement
         | 
| 136 | 
            +
                      # for range matching
         | 
| 137 | 
            +
                      requirements = requirement.split(",").map(&:strip)
         | 
| 138 | 
            +
                      if requirements.all? { |r| Gem::Requirement::PATTERN.match?(r) }
         | 
| 139 | 
            +
                        requirement = Gem::Requirement.new(requirements)
         | 
| 140 | 
            +
                      end
         | 
| 120 141 | 
             
                    end
         | 
| 121 142 |  | 
| 122 | 
            -
                     | 
| 143 | 
            +
                    # the pattern's name must match the dependency's name
         | 
| 144 | 
            +
                    next false unless File.fnmatch?(name, dependency["name"], File::FNM_PATHNAME | File::FNM_CASEFOLD)
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                    # if there is no version requirement configured or if the dependency doesn't have a version
         | 
| 147 | 
            +
                    # specified, return a value based on whether a version match is required
         | 
| 148 | 
            +
                    next !require_version if requirement.nil? || dependency["version"].to_s.empty?
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                    case requirement
         | 
| 151 | 
            +
                    when String
         | 
| 152 | 
            +
                      # string match the requirement against "*" or the dependency's version
         | 
| 153 | 
            +
                      [ANY_VERSION_REQUIREMENT, dependency["version"]].any? { |r| requirement == r }
         | 
| 154 | 
            +
                    when Gem::Requirement
         | 
| 155 | 
            +
                      # if the version was parsed as a gem requirement, check whether the version requirement
         | 
| 156 | 
            +
                      # matches the dependency's version
         | 
| 157 | 
            +
                      Gem::Version.correct?(dependency["version"]) && requirement.satisfied_by?(Gem::Version.new(dependency["version"]))
         | 
| 158 | 
            +
                    end
         | 
| 123 159 | 
             
                  end
         | 
| 124 160 | 
             
                end
         | 
| 125 161 |  | 
    
        data/lib/licensed/dependency.rb
    CHANGED
    
    | @@ -9,6 +9,7 @@ module Licensed | |
| 9 9 | 
             
                attr_reader :version
         | 
| 10 10 | 
             
                attr_reader :errors
         | 
| 11 11 | 
             
                attr_reader :path
         | 
| 12 | 
            +
                attr_reader :additional_terms
         | 
| 12 13 |  | 
| 13 14 | 
             
                # Create a new project dependency
         | 
| 14 15 | 
             
                #
         | 
| @@ -28,6 +29,7 @@ module Licensed | |
| 28 29 | 
             
                  @errors = errors
         | 
| 29 30 | 
             
                  path = path.to_s
         | 
| 30 31 | 
             
                  @path = path
         | 
| 32 | 
            +
                  @additional_terms = []
         | 
| 31 33 |  | 
| 32 34 | 
             
                  # enforcing absolute paths makes life much easier when determining
         | 
| 33 35 | 
             
                  # an absolute file path in #notices
         | 
| @@ -80,6 +82,13 @@ module Licensed | |
| 80 82 | 
             
                  files.compact
         | 
| 81 83 | 
             
                end
         | 
| 82 84 |  | 
| 85 | 
            +
             | 
| 86 | 
            +
                # Override the behavior of Licensee::Projects::FSProject#project_files to include
         | 
| 87 | 
            +
                # additional license terms
         | 
| 88 | 
            +
                def project_files
         | 
| 89 | 
            +
                  super + additional_license_terms_files
         | 
| 90 | 
            +
                end
         | 
| 91 | 
            +
             | 
| 83 92 | 
             
                # Returns legal notices found at the dependency path
         | 
| 84 93 | 
             
                def notice_contents
         | 
| 85 94 | 
             
                  Dir.glob(dir_path.join("*"))
         | 
| @@ -90,6 +99,17 @@ module Licensed | |
| 90 99 | 
             
                     .select { |notice| notice["text"].length > 0 } # files with content only
         | 
| 91 100 | 
             
                end
         | 
| 92 101 |  | 
| 102 | 
            +
                # Returns a hash of basic metadata about the dependency - name, version, type, etc
         | 
| 103 | 
            +
                def metadata
         | 
| 104 | 
            +
                  {
         | 
| 105 | 
            +
                    # can be overriden by values in @metadata
         | 
| 106 | 
            +
                    "name" => name,
         | 
| 107 | 
            +
                    "version" => version
         | 
| 108 | 
            +
                  }.merge(
         | 
| 109 | 
            +
                    @metadata
         | 
| 110 | 
            +
                  )
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
             | 
| 93 113 | 
             
                private
         | 
| 94 114 |  | 
| 95 115 | 
             
                def read_file_with_encoding_check(file_path)
         | 
| @@ -102,6 +122,7 @@ module Licensed | |
| 102 122 | 
             
                def license_content_sources(files)
         | 
| 103 123 | 
             
                  paths = Array(files).map do |file|
         | 
| 104 124 | 
             
                    next file[:uri] if file[:uri]
         | 
| 125 | 
            +
                    next file[:source] if file[:source]
         | 
| 105 126 |  | 
| 106 127 | 
             
                    path = dir_path.join(file[:dir], file[:name])
         | 
| 107 128 | 
             
                    normalize_source_path(path)
         | 
| @@ -125,14 +146,8 @@ module Licensed | |
| 125 146 | 
             
                # Returns the metadata that represents this dependency.  This metadata
         | 
| 126 147 | 
             
                # is written to YAML in the dependencys cached text file
         | 
| 127 148 | 
             
                def license_metadata
         | 
| 128 | 
            -
                  {
         | 
| 129 | 
            -
                    #  | 
| 130 | 
            -
                    "name" => name,
         | 
| 131 | 
            -
                    "version" => version
         | 
| 132 | 
            -
                  }.merge(
         | 
| 133 | 
            -
                    @metadata
         | 
| 134 | 
            -
                  ).merge({
         | 
| 135 | 
            -
                    # overrides all other values
         | 
| 149 | 
            +
                  metadata.merge({
         | 
| 150 | 
            +
                    # overrides all metadata values
         | 
| 136 151 | 
             
                    "license" => license_key
         | 
| 137 152 | 
             
                  })
         | 
| 138 153 | 
             
                end
         | 
| @@ -157,5 +172,22 @@ module Licensed | |
| 157 172 | 
             
                    "text" => text
         | 
| 158 173 | 
             
                  }
         | 
| 159 174 | 
             
                end
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                # Returns an array of Licensee::ProjectFiles::LicenseFile created from
         | 
| 177 | 
            +
                # this dependency's additional license terms
         | 
| 178 | 
            +
                def additional_license_terms_files
         | 
| 179 | 
            +
                  @additional_license_terms_files ||= begin
         | 
| 180 | 
            +
                    files = additional_terms.map do |path|
         | 
| 181 | 
            +
                      next unless File.file?(path)
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                      metadata = { dir: File.dirname(path), name: File.basename(path) }
         | 
| 184 | 
            +
                      Licensee::ProjectFiles::LicenseFile.new(
         | 
| 185 | 
            +
                        load_file(metadata),
         | 
| 186 | 
            +
                        { source: "License terms loaded from #{metadata[:name]}" }
         | 
| 187 | 
            +
                      )
         | 
| 188 | 
            +
                    end
         | 
| 189 | 
            +
                    files.compact
         | 
| 190 | 
            +
                  end
         | 
| 191 | 
            +
                end
         | 
| 160 192 | 
             
              end
         | 
| 161 193 | 
             
            end
         | 
| @@ -9,7 +9,7 @@ require "fileutils" | |
| 9 9 | 
             
            module Licensed
         | 
| 10 10 | 
             
              module Sources
         | 
| 11 11 | 
             
                class Gradle < Source
         | 
| 12 | 
            -
                  DEFAULT_CONFIGURATIONS   = [" | 
| 12 | 
            +
                  DEFAULT_CONFIGURATIONS   = ["runtimeOnly", "runtimeClasspath"].freeze
         | 
| 13 13 | 
             
                  GRADLE_LICENSES_PATH     = ".gradle-licenses".freeze
         | 
| 14 14 | 
             
                  GRADLE_LICENSES_CSV_NAME = "licenses.csv".freeze
         | 
| 15 15 | 
             
                  class Dependency < Licensed::Dependency
         | 
| @@ -46,7 +46,7 @@ module Licensed | |
| 46 46 | 
             
                  end
         | 
| 47 47 |  | 
| 48 48 | 
             
                  def enumerate_dependencies
         | 
| 49 | 
            -
                    JSON.parse(gradle_runner.run("printDependencies" | 
| 49 | 
            +
                    JSON.parse(gradle_runner.run("printDependencies")).map do |package|
         | 
| 50 50 | 
             
                      name = "#{package['group']}:#{package['name']}"
         | 
| 51 51 | 
             
                      Dependency.new(
         | 
| 52 52 | 
             
                        name: name,
         | 
| @@ -73,7 +73,7 @@ module Licensed | |
| 73 73 | 
             
                  end
         | 
| 74 74 |  | 
| 75 75 | 
             
                  def gradle_runner
         | 
| 76 | 
            -
                    @gradle_runner ||= Runner.new( | 
| 76 | 
            +
                    @gradle_runner ||= Runner.new(configurations, executable)
         | 
| 77 77 | 
             
                  end
         | 
| 78 78 |  | 
| 79 79 | 
             
                  # Returns the configurations to include in license generation.
         | 
| @@ -113,7 +113,7 @@ module Licensed | |
| 113 113 | 
             
                    begin
         | 
| 114 114 | 
             
                      # create the CSV file including dependency license urls using the gradle plugin
         | 
| 115 115 | 
             
                      gradle_licenses_dir = File.join(config.root, GRADLE_LICENSES_PATH)
         | 
| 116 | 
            -
                      gradle_runner.run("generateLicenseReport" | 
| 116 | 
            +
                      gradle_runner.run("generateLicenseReport")
         | 
| 117 117 |  | 
| 118 118 | 
             
                      # parse the CSV report for dependency license urls
         | 
| 119 119 | 
             
                      CSV.foreach(File.join(gradle_licenses_dir, GRADLE_LICENSES_CSV_NAME), headers: true).each_with_object({}) do |row, hsh|
         | 
| @@ -134,80 +134,82 @@ module Licensed | |
| 134 134 | 
             
                  # The Gradle::Runner class is a wrapper which provides
         | 
| 135 135 | 
             
                  # an interface to run gradle commands with the init script initialized
         | 
| 136 136 | 
             
                  class Runner
         | 
| 137 | 
            -
                    def initialize( | 
| 138 | 
            -
                      @root_path = root_path
         | 
| 137 | 
            +
                    def initialize(configurations, executable)
         | 
| 139 138 | 
             
                      @executable = executable
         | 
| 140 | 
            -
                      @init_script = create_init_script( | 
| 139 | 
            +
                      @init_script = create_init_script(configurations)
         | 
| 141 140 | 
             
                    end
         | 
| 142 141 |  | 
| 143 | 
            -
                    def run(command | 
| 144 | 
            -
                      args = [ | 
| 142 | 
            +
                    def run(command)
         | 
| 143 | 
            +
                      args = [command]
         | 
| 145 144 | 
             
                      # The configuration cache is an incubating feature that can be activated manually.
         | 
| 146 145 | 
             
                      # The gradle plugin for licenses does not support it so we prevent it to run for gradle version supporting it.
         | 
| 147 | 
            -
                      args << "--no-configuration-cache" if gradle_version >= "6.6"
         | 
| 146 | 
            +
                      args << "--no-configuration-cache" if gradle_version >= Gem::Version.new("6.6")
         | 
| 148 147 | 
             
                      Licensed::Shell.execute(@executable, "-q", "--init-script", @init_script.path, *args)
         | 
| 149 148 | 
             
                    end
         | 
| 150 149 |  | 
| 151 150 | 
             
                    private
         | 
| 152 151 |  | 
| 153 | 
            -
                    def  | 
| 154 | 
            -
                       | 
| 155 | 
            -
             | 
| 156 | 
            -
             | 
| 157 | 
            -
             | 
| 158 | 
            -
             | 
| 159 | 
            -
             | 
| 160 | 
            -
             | 
| 161 | 
            -
             | 
| 162 | 
            -
             | 
| 163 | 
            -
             | 
| 164 | 
            -
             | 
| 165 | 
            -
             | 
| 166 | 
            -
             | 
| 167 | 
            -
             | 
| 168 | 
            -
             | 
| 169 | 
            -
             | 
| 170 | 
            -
                                  }
         | 
| 171 | 
            -
                                }
         | 
| 172 | 
            -
                                dependencies {
         | 
| 173 | 
            -
                                  classpath "com.github.jk1:gradle-license-report:#{gradle_version >= "7.0" ? "2.0" : "1.17"}"
         | 
| 152 | 
            +
                    def create_init_script(configurations)
         | 
| 153 | 
            +
                      # we need to create extensions in the event that the user hasn't configured custom configurations
         | 
| 154 | 
            +
                      # to avoid hitting errors where core Gradle configurations are set with canBeResolved=false
         | 
| 155 | 
            +
                      configuration_map = configurations.map { |c| [c, "licensed#{c}"] }.to_h
         | 
| 156 | 
            +
                      configuration_dsl = configuration_map.map { |orig, custom| "#{custom}.extendsFrom(#{orig})" }
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                      f = Tempfile.new(["init", ".gradle"])
         | 
| 159 | 
            +
                      f.write(
         | 
| 160 | 
            +
                        <<~EOF
         | 
| 161 | 
            +
                            import com.github.jk1.license.render.CsvReportRenderer
         | 
| 162 | 
            +
                            import com.github.jk1.license.filter.LicenseBundleNormalizer
         | 
| 163 | 
            +
                            final configs = #{configuration_map.values.inspect}
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                            initscript {
         | 
| 166 | 
            +
                              repositories {
         | 
| 167 | 
            +
                                maven {
         | 
| 168 | 
            +
                                  url "https://plugins.gradle.org/m2/"
         | 
| 174 169 | 
             
                                }
         | 
| 175 170 | 
             
                              }
         | 
| 171 | 
            +
                              dependencies {
         | 
| 172 | 
            +
                                classpath "com.github.jk1:gradle-license-report:#{gradle_version >= Gem::Version.new("7.0") ? "2.0" : "1.17"}"
         | 
| 173 | 
            +
                              }
         | 
| 174 | 
            +
                            }
         | 
| 176 175 |  | 
| 177 | 
            -
             | 
| 178 | 
            -
             | 
| 179 | 
            -
                                 | 
| 180 | 
            -
             | 
| 181 | 
            -
             | 
| 182 | 
            -
             | 
| 183 | 
            -
             | 
| 184 | 
            -
             | 
| 176 | 
            +
                            allprojects {
         | 
| 177 | 
            +
                              configurations {
         | 
| 178 | 
            +
                                #{configuration_dsl.join("\n") }
         | 
| 179 | 
            +
                              }
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                              apply plugin: com.github.jk1.license.LicenseReportPlugin
         | 
| 182 | 
            +
                              licenseReport {
         | 
| 183 | 
            +
                                  outputDir = "$rootDir/#{GRADLE_LICENSES_PATH}"
         | 
| 184 | 
            +
                                  configurations = configs
         | 
| 185 | 
            +
                                  renderers = [new CsvReportRenderer()]
         | 
| 186 | 
            +
                                  filters = [new LicenseBundleNormalizer()]
         | 
| 187 | 
            +
                              }
         | 
| 185 188 |  | 
| 186 | 
            -
             | 
| 187 | 
            -
             | 
| 188 | 
            -
             | 
| 189 | 
            -
             | 
| 190 | 
            -
             | 
| 191 | 
            -
             | 
| 192 | 
            -
             | 
| 193 | 
            -
             | 
| 194 | 
            -
             | 
| 195 | 
            -
             | 
| 196 | 
            -
                                  }
         | 
| 189 | 
            +
                              task printDependencies {
         | 
| 190 | 
            +
                                doLast {
         | 
| 191 | 
            +
                                    def dependencies = []
         | 
| 192 | 
            +
                                    configs.each {
         | 
| 193 | 
            +
                                        configurations[it].resolvedConfiguration.resolvedArtifacts.each { artifact ->
         | 
| 194 | 
            +
                                            def id = artifact.moduleVersion.id
         | 
| 195 | 
            +
                                            dependencies << "{ \\"group\\": \\"${id.group}\\", \\"name\\": \\"${id.name}\\", \\"version\\": \\"${id.version}\\" }"
         | 
| 196 | 
            +
                                        }
         | 
| 197 | 
            +
                                    }
         | 
| 198 | 
            +
                                    println "[${dependencies.join(", ")}]"
         | 
| 197 199 | 
             
                                }
         | 
| 198 200 | 
             
                              }
         | 
| 199 | 
            -
                             | 
| 200 | 
            -
                           | 
| 201 | 
            -
                         | 
| 202 | 
            -
             | 
| 203 | 
            -
                       | 
| 201 | 
            +
                            }
         | 
| 202 | 
            +
                          EOF
         | 
| 203 | 
            +
                        )
         | 
| 204 | 
            +
                      f.close
         | 
| 205 | 
            +
                      f
         | 
| 204 206 | 
             
                    end
         | 
| 205 207 |  | 
| 206 | 
            -
                    #  | 
| 207 | 
            -
                    def  | 
| 208 | 
            -
                       | 
| 209 | 
            -
                         | 
| 210 | 
            -
                         | 
| 208 | 
            +
                    # Returns the version of gradle used during execution
         | 
| 209 | 
            +
                    def gradle_version
         | 
| 210 | 
            +
                      @gradle_version ||= begin
         | 
| 211 | 
            +
                        version = Licensed::Shell.execute(@executable, "--version").scan(/Gradle [\d+]\.[\d+]/).last.split(" ").last
         | 
| 212 | 
            +
                        Gem::Version.new(version)
         | 
| 211 213 | 
             
                      end
         | 
| 212 214 | 
             
                    end
         | 
| 213 215 | 
             
                  end
         | 
| @@ -0,0 +1,58 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
            require "json"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Licensed
         | 
| 5 | 
            +
              module Sources
         | 
| 6 | 
            +
                class PNPM < Source
         | 
| 7 | 
            +
                  # The PNPM source requires matching reviewed or ignored dependencies
         | 
| 8 | 
            +
                  # on both name and version
         | 
| 9 | 
            +
                  def self.require_matched_dependency_version
         | 
| 10 | 
            +
                    true
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  # Returns true when pnpm is installed and a pnpm-lock.yaml file is found,
         | 
| 14 | 
            +
                  # otherwise false
         | 
| 15 | 
            +
                  def enabled?
         | 
| 16 | 
            +
                    return false unless Licensed::Shell.tool_available?("pnpm")
         | 
| 17 | 
            +
                    File.exist?(File.join(config.pwd, "pnpm-lock.yaml"))
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def enumerate_dependencies
         | 
| 21 | 
            +
                    packages.map do |package|
         | 
| 22 | 
            +
                      name_with_version = "#{package["name"]}@#{package["version"]}"
         | 
| 23 | 
            +
                      Dependency.new(
         | 
| 24 | 
            +
                        name: name_with_version,
         | 
| 25 | 
            +
                        version: package["version"],
         | 
| 26 | 
            +
                        path: package["path"],
         | 
| 27 | 
            +
                        metadata: {
         | 
| 28 | 
            +
                          "type"     => PNPM.type,
         | 
| 29 | 
            +
                          "name"     => package["name"],
         | 
| 30 | 
            +
                          "summary"  => package["description"],
         | 
| 31 | 
            +
                          "homepage" => package["homepage"]
         | 
| 32 | 
            +
                        }
         | 
| 33 | 
            +
                      )
         | 
| 34 | 
            +
                    end
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  # Returns package metadata returned from `pnpm licensed list`
         | 
| 38 | 
            +
                  def packages
         | 
| 39 | 
            +
                    JSON.parse(package_metadata_command).values.flatten
         | 
| 40 | 
            +
                  rescue JSON::ParserError => e
         | 
| 41 | 
            +
                    message = "Licensed was unable to parse the output from 'pnpm licenses list'. JSON Error: #{e.message}"
         | 
| 42 | 
            +
                    raise Licensed::Sources::Source::Error, message
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  # Returns the output from running `pnpm licenses list` to get package metadata
         | 
| 46 | 
            +
                  def package_metadata_command
         | 
| 47 | 
            +
                    args = %w(--json --long)
         | 
| 48 | 
            +
                    args << "--prod" unless include_non_production?
         | 
| 49 | 
            +
                    Licensed::Shell.execute("pnpm", "licenses", "list", *args, allow_failure: true)
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  # Returns whether to include non production dependencies based on the licensed configuration settings
         | 
| 53 | 
            +
                  def include_non_production?
         | 
| 54 | 
            +
                    config.dig("pnpm", "production_only") == false
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
            end
         | 
| @@ -51,6 +51,12 @@ module Licensed | |
| 51 51 | 
             
                               .downcase
         | 
| 52 52 | 
             
                               .split("::")
         | 
| 53 53 | 
             
                    end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                    # Returns true if the source requires matching reviewed and ignored dependencies'
         | 
| 56 | 
            +
                    # versions as well as their name
         | 
| 57 | 
            +
                    def require_matched_dependency_version
         | 
| 58 | 
            +
                      false
         | 
| 59 | 
            +
                    end
         | 
| 54 60 | 
             
                  end
         | 
| 55 61 |  | 
| 56 62 | 
             
                  # all sources have a configuration
         | 
| @@ -69,7 +75,9 @@ module Licensed | |
| 69 75 | 
             
                  # Returns all dependencies that should be evaluated.
         | 
| 70 76 | 
             
                  # Excludes ignored dependencies.
         | 
| 71 77 | 
             
                  def dependencies
         | 
| 72 | 
            -
                    cached_dependencies | 
| 78 | 
            +
                    cached_dependencies
         | 
| 79 | 
            +
                      .reject { |d| ignored?(d) }
         | 
| 80 | 
            +
                      .each { |d| add_additional_terms_from_configuration(d) }
         | 
| 73 81 | 
             
                  end
         | 
| 74 82 |  | 
| 75 83 | 
             
                  # Enumerate all source dependencies.  Must be implemented by each source class.
         | 
| @@ -79,7 +87,7 @@ module Licensed | |
| 79 87 |  | 
| 80 88 | 
             
                  # Returns whether a dependency is ignored in the configuration.
         | 
| 81 89 | 
             
                  def ignored?(dependency)
         | 
| 82 | 
            -
                    config.ignored?( | 
| 90 | 
            +
                    config.ignored?(dependency.metadata, require_version: self.class.require_matched_dependency_version)
         | 
| 83 91 | 
             
                  end
         | 
| 84 92 |  | 
| 85 93 | 
             
                  private
         | 
| @@ -88,6 +96,11 @@ module Licensed | |
| 88 96 | 
             
                  def cached_dependencies
         | 
| 89 97 | 
             
                    @dependencies ||= enumerate_dependencies.compact
         | 
| 90 98 | 
             
                  end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                  # Add any additional_terms for this dependency that have been added to the configuration
         | 
| 101 | 
            +
                  def add_additional_terms_from_configuration(dependency)
         | 
| 102 | 
            +
                    dependency.additional_terms.concat config.additional_terms_for_dependency("type" => self.class.type, "name" => dependency.name)
         | 
| 103 | 
            +
                  end
         | 
| 91 104 | 
             
                end
         | 
| 92 105 | 
             
              end
         | 
| 93 106 | 
             
            end
         | 
    
        data/lib/licensed/sources.rb
    CHANGED
    
    | @@ -6,19 +6,20 @@ module Licensed | |
| 6 6 | 
             
                require "licensed/sources/bundler"
         | 
| 7 7 | 
             
                require "licensed/sources/cabal"
         | 
| 8 8 | 
             
                require "licensed/sources/cargo"
         | 
| 9 | 
            +
                require "licensed/sources/cocoapods"
         | 
| 9 10 | 
             
                require "licensed/sources/composer"
         | 
| 10 11 | 
             
                require "licensed/sources/dep"
         | 
| 11 12 | 
             
                require "licensed/sources/git_submodule"
         | 
| 12 13 | 
             
                require "licensed/sources/go"
         | 
| 14 | 
            +
                require "licensed/sources/gradle"
         | 
| 13 15 | 
             
                require "licensed/sources/manifest"
         | 
| 16 | 
            +
                require "licensed/sources/mix"
         | 
| 14 17 | 
             
                require "licensed/sources/npm"
         | 
| 15 18 | 
             
                require "licensed/sources/nuget"
         | 
| 16 19 | 
             
                require "licensed/sources/pip"
         | 
| 17 20 | 
             
                require "licensed/sources/pipenv"
         | 
| 21 | 
            +
                require "licensed/sources/pnpm"
         | 
| 18 22 | 
             
                require "licensed/sources/swift"
         | 
| 19 | 
            -
                require "licensed/sources/gradle"
         | 
| 20 | 
            -
                require "licensed/sources/mix"
         | 
| 21 23 | 
             
                require "licensed/sources/yarn"
         | 
| 22 | 
            -
                require "licensed/sources/cocoapods"
         | 
| 23 24 | 
             
              end
         | 
| 24 25 | 
             
            end
         | 
    
        data/lib/licensed/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: licensed
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 4.0 | 
| 4 | 
            +
              version: 4.2.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - GitHub
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2023- | 
| 11 | 
            +
            date: 2023-02-25 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: licensee
         | 
| @@ -219,6 +219,7 @@ files: | |
| 219 219 | 
             
            - docs/commands/version.md
         | 
| 220 220 | 
             
            - docs/configuration.md
         | 
| 221 221 | 
             
            - docs/configuration/README.md
         | 
| 222 | 
            +
            - docs/configuration/additional_terms.md
         | 
| 222 223 | 
             
            - docs/configuration/allowed_licenses.md
         | 
| 223 224 | 
             
            - docs/configuration/application_name.md
         | 
| 224 225 | 
             
            - docs/configuration/application_source.md
         | 
| @@ -249,6 +250,7 @@ files: | |
| 249 250 | 
             
            - docs/sources/nuget.md
         | 
| 250 251 | 
             
            - docs/sources/pip.md
         | 
| 251 252 | 
             
            - docs/sources/pipenv.md
         | 
| 253 | 
            +
            - docs/sources/pnpm.md
         | 
| 252 254 | 
             
            - docs/sources/stack.md
         | 
| 253 255 | 
             
            - docs/sources/swift.md
         | 
| 254 256 | 
             
            - docs/sources/yarn.md
         | 
| @@ -298,6 +300,7 @@ files: | |
| 298 300 | 
             
            - lib/licensed/sources/nuget.rb
         | 
| 299 301 | 
             
            - lib/licensed/sources/pip.rb
         | 
| 300 302 | 
             
            - lib/licensed/sources/pipenv.rb
         | 
| 303 | 
            +
            - lib/licensed/sources/pnpm.rb
         | 
| 301 304 | 
             
            - lib/licensed/sources/source.rb
         | 
| 302 305 | 
             
            - lib/licensed/sources/swift.rb
         | 
| 303 306 | 
             
            - lib/licensed/sources/yarn.rb
         |