summaryrefslogtreecommitdiff
path: root/lib/license/management/report/v1.rb
blob: 49423c6fbf30528ce54c1d9b0a5bc78092a14871 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# frozen_string_literal: true

module License
  module Management
    module Report
      class V1 < Base
        def to_h
          {
            licenses: license_summary,
            dependencies: formatted_dependencies(dependencies)
          }
        end

        private

        # when a dependency has multiple licenses, this will join the licenses into a single name
        # this defect was backported from the [html2json](https://gitlab.com/gitlab-org/security-products/license-management/blob/7f175952a5a047d785b5ea72c15a10642523c62a/html2json.js) version of this script.
        def license_summary
          dependencies
            .map { |dependency| join_license_names(dependency.licenses) }
            .flatten
            .group_by { |name| name }
            .map { |license, items| { count: items.count, name: license } }
            .sort_by { |hash| [-hash[:count], hash[:name]] }
        end

        # when a dependency has more than one license
        # this method chooses one of the urls.
        # to maintain backwards compatibility this bug has been carried forward.
        def license_for(dependency)
          license = { name: join_license_names(dependency.licenses) }

          urls = dependency.licenses.map(&:url).reject { |x| blank?(x) }.uniq.sort
          log_info("multiple urls detected: #{urls.inspect}") if urls.size > 1
          url = urls[0] || license_data(dependency.licenses.first)['url']

          license[:url] = url if present?(url)
          license
        end

        def join_license_names(licenses)
          licenses.map { |x| best_name_for(x) }.sort.reverse.join(', ')
        end

        def map_from_dependency(dependency)
          result = {
            license: license_for(dependency),
            dependency: {
              name: dependency.name,
              url: dependency.homepage,
              description: description_for(dependency),
              pathes: paths_from(dependency)
            }
          }
          result[:dependency].delete(:url) if blank?(dependency.homepage)
          result
        end

        def formatted_dependencies(dependencies)
          dependencies.map { |x| map_from_dependency(x) }
        end

        def best_name_for(license)
          license_data(license)['name']
        end

        def license_data(license)
          {
            'name' => license.name.split(/[\r\n]+/)[0],
            'url' => license.url || ''
          }
        end
      end
    end
  end
end