diff options
| author | mo khan <mkhan@gitlab.com> | 2019-09-12 15:55:59 +0000 |
|---|---|---|
| committer | mo khan <mkhan@gitlab.com> | 2019-09-12 15:55:59 +0000 |
| commit | fa7a0dd6496b119b6f143ef8deba177b16f53d1c (patch) | |
| tree | f3f0738459d180a9ffa91c84c214ac75230774ff | |
| parent | 8865a0bc643fdf4d3b679aff84e4f83ba2617936 (diff) | |
| parent | caa6ce0445aec8618924b41f7700173722e37d85 (diff) | |
Merge branch '13083-ruby-shim' into 'master'
Insert a shim to start generating v1 reports using the license finder Ruby API
See merge request gitlab-org/security-products/license-management!55
29 files changed, 545 insertions, 30 deletions
diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..1d4e811 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +.git +.env.* diff --git a/.env.12-2-stable b/.env.12-2-stable new file mode 100644 index 0000000..3e94bc7 --- /dev/null +++ b/.env.12-2-stable @@ -0,0 +1,3 @@ +FEATURE_RUBY_REPORT 'false' +LM_REPORT_VERSION 1 +LM_V1_CANONICALIZE 'false' diff --git a/.env.12-3-stable b/.env.12-3-stable new file mode 100644 index 0000000..edb6a67 --- /dev/null +++ b/.env.12-3-stable @@ -0,0 +1,3 @@ +FEATURE_RUBY_REPORT 'true' +LM_REPORT_VERSION 1 +LM_V1_CANONICALIZE 'false' diff --git a/.env.legacy b/.env.legacy new file mode 100644 index 0000000..bba5f11 --- /dev/null +++ b/.env.legacy @@ -0,0 +1,4 @@ +FEATURE_RUBY_REPORT 'false' +LM_PYTHON_VERSION 2.7 +LM_REPORT_VERSION 1 +LM_V1_CANONICALIZE 'false' diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8462f59 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +tmp +Dockerfile.env diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1a315b3..740b520 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -35,13 +35,15 @@ container_scanning: image: docker:stable stage: test variables: + FEATURE_RUBY_REPORT: 'false' LM_PYTHON_VERSION: 3 + LM_REPORT_VERSION: 1 script: - docker info - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY - docker pull $TMP_IMAGE - mkdir results - - docker run --env LM_PYTHON_VERSION --volume `pwd`/results:/results $TMP_IMAGE test $QA_PROJECT ${QA_RESULTS:-$QA_PROJECT} $QA_REF + - ./bin/test artifacts: paths: - results/ @@ -63,7 +65,7 @@ QA:python-pip: QA:python3-pip: extends: .QA variables: - QA_RESULTS: python3-pip + QA_RESULTS: python3-pip-v1 QA_PROJECT: python-pip QA_REF: 48e250a1 @@ -93,8 +95,13 @@ QA:js: - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY - export SOURCE_IMAGE=$TMP_IMAGE - export TARGET_IMAGE=$CI_REGISTRY_IMAGE:${IMAGE_TAG:-$CI_JOB_NAME} - - docker pull $SOURCE_IMAGE - - docker tag $SOURCE_IMAGE $TARGET_IMAGE + - | + if [ -z "$DOTENV" ]; then + docker pull $SOURCE_IMAGE + docker tag $SOURCE_IMAGE $TARGET_IMAGE + else + ./bin/docker-dotenv + fi - docker push $TARGET_IMAGE .docker_tag_python2: @@ -155,12 +162,6 @@ version python2: only: - tags -.release_python2: - extends: .docker_tag_python2 - stage: release - only: - - tags - major: extends: .release variables: @@ -171,48 +172,80 @@ latest: 12-3-stable: extends: .release + variables: + DOTENV: ".env.12-3-stable" 12-2-stable: extends: .release + variables: + DOTENV: ".env.12-2-stable" 12-1-stable: - extends: .release_python2 + extends: .release + variables: + DOTENV: ".env.legacy" 12-0-stable: - extends: .release_python2 + extends: .release + variables: + DOTENV: ".env.legacy" 11-11-stable: - extends: .release_python2 + extends: .release + variables: + DOTENV: ".env.legacy" 11-10-stable: - extends: .release_python2 + extends: .release + variables: + DOTENV: ".env.legacy" 11-9-stable: - extends: .release_python2 + extends: .release + variables: + DOTENV: ".env.legacy" 11-8-stable: - extends: .release_python2 + extends: .release + variables: + DOTENV: ".env.legacy" 11-7-stable: - extends: .release_python2 + extends: .release + variables: + DOTENV: ".env.legacy" 11-6-stable: - extends: .release_python2 + extends: .release + variables: + DOTENV: ".env.legacy" 11-5-stable: - extends: .release_python2 + extends: .release + variables: + DOTENV: ".env.legacy" 11-4-stable: - extends: .release_python2 + extends: .release + variables: + DOTENV: ".env.legacy" 11-3-stable: - extends: .release_python2 + extends: .release + variables: + DOTENV: ".env.legacy" 11-2-stable: - extends: .release_python2 + extends: .release + variables: + DOTENV: ".env.legacy" 11-1-stable: - extends: .release_python2 + extends: .release + variables: + DOTENV: ".env.legacy" 11-0-stable: - extends: .release_python2 + extends: .release + variables: + DOTENV: ".env.legacy" diff --git a/CHANGELOG.md b/CHANGELOG.md index ac4f1eb..53d08d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # GitLab License management changelog +## v1.7.0 + +- Convert HTML to JSON transformation to generating a JSON report directly. + ## v1.6.1 - Fix `The engine "node" is incompatible with this module.` error (!61) @@ -22,6 +22,9 @@ RUN apt-get update && \ libpq-dev libmysqlclient-dev realpath python3-dev python3-pip && \ rm -rf /var/lib/apt/lists/* +COPY . /opt/license-management/ +RUN bash -lc "cd /opt/license-management && gem build *.gemspec && gem install *.gem" + # Don't load RVM automatically, it doesn't work with GitLab-CI RUN mv /etc/profile.d/rvm.sh /rvm.sh @@ -43,6 +46,7 @@ RUN pip3 install --disable-pip-version-check setuptools==$SETUPTOOLS_VERSION && # Version of Python, defaults to Python 3.5 ARG LM_PYTHON_VERSION=3.5 ENV LM_PYTHON_VERSION $LM_PYTHON_VERSION +ENV LM_REPORT_VERSION ${LM_REPORT_VERSION:-1} COPY test /test COPY run.sh html2json.js / @@ -40,7 +40,7 @@ docker run --rm --volume "/path/to/my/project":/code license-management analyze You can run integration tests on the image like this: ```sh -docker run --rm license-management /test/test.sh project_name git_ref +./bin/test_all ``` where: diff --git a/bin/docker-dotenv b/bin/docker-dotenv new file mode 100755 index 0000000..ca025c0 --- /dev/null +++ b/bin/docker-dotenv @@ -0,0 +1,33 @@ +#!/bin/sh + +# input: +# SOURCE_IMAGE: Image name for the source image +# TARGET_IMAGE: Name of image to build +# DOTENV: The name of the .env.* file that contains the default env vars to export. +# e.g. DOTENV=".env.12-3-stable" + +set -e + +cd "$(dirname "$0")/.." +DOCKERFILE=Dockerfile.env + +rm -f $DOCKERFILE +touch $DOCKERFILE +echo "FROM $SOURCE_IMAGE" > $DOCKERFILE + +echo "Reading... $DOTENV" +cat $DOTENV + +while IFS= read -r line; do + echo "ENV $line" >> $DOCKERFILE +done < $DOTENV + +echo "Pulling... $SOURCE_IMAGE" +docker pull $SOURCE_IMAGE + +echo "Building... $DOCKERFILE and tagging $TARGET_IMAGE" +cat $DOCKERFILE +docker build -t $TARGET_IMAGE -f $DOCKERFILE . + +echo "Verifying env..." +docker run --entrypoint='' $TARGET_IMAGE env diff --git a/bin/test b/bin/test new file mode 100755 index 0000000..c1cd989 --- /dev/null +++ b/bin/test @@ -0,0 +1,17 @@ +#!/bin/sh + +set -e + +export FEATURE_RUBY_REPORT=${FEATURE_RUBY_REPORT:-true} +export LM_PYTHON_VERSION=${LM_PYTHON_VERSION:-2} +export LM_REPORT_VERSION=${LM_REPORT_VERSION:-1} +export QA_RESULTS=${QA_RESULTS:-$QA_PROJECT-v$LM_REPORT_VERSION} +export RESULTS_DIR=${RESULTS_DIR:-`pwd`/results} + +docker run \ + --rm \ + --env FEATURE_RUBY_REPORT \ + --env LM_PYTHON_VERSION \ + --env LM_REPORT_VERSION \ + --volume $RESULTS_DIR:/results \ + $TMP_IMAGE test $QA_PROJECT ${QA_RESULTS} $QA_REF diff --git a/bin/test_all b/bin/test_all new file mode 100755 index 0000000..c96c2e1 --- /dev/null +++ b/bin/test_all @@ -0,0 +1,20 @@ +#!/bin/sh + +set -e + +export RESULTS_DIR=`pwd`/tmp +export TMP_IMAGE=$(basename $PWD):latest + +docker build . -t $TMP_IMAGE --pull + +REPORT_VERSIONS=(1) +for version in "${REPORT_VERSIONS[@]}" +do + export LM_REPORT_VERSION=$version + echo "Report Version $LM_REPORT_VERSION" + QA_PROJECT=go-modules QA_REF=master ./bin/test + QA_PROJECT=java-maven QA_REF=831c7a04 ./bin/test + QA_PROJECT=python-pip QA_REF=04dce91b LM_PYTHON_VERSION=2 ./bin/test + QA_PROJECT=python-pip QA_RESULTS="python3-pip-v$version" QA_REF=48e250a1 LM_PYTHON_VERSION=3 ./bin/test + QA_PROJECT=ruby-bundler QA_REF=6b858821 ./bin/test +done diff --git a/exe/license_management b/exe/license_management new file mode 100755 index 0000000..33e110e --- /dev/null +++ b/exe/license_management @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'license/management' + +LicenseFinder::CLI::Main.start(ARGV) diff --git a/lib/license/management.rb b/lib/license/management.rb new file mode 100644 index 0000000..64fd4e8 --- /dev/null +++ b/lib/license/management.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'pathname' +require 'yaml' +require 'license_finder' +require 'license/management/loggable' +require 'license/management/verifiable' +require 'license/management/repository' +require 'license/management/report' +require 'license/management/version' + +# This applies a monkey patch to the JsonReport found in the `license_finder` gem. +LicenseFinder::JsonReport.prepend(License::Management::Report) + +module License + module Management + def self.root + Pathname.new(File.dirname(__FILE__)).join('../..') + end + end +end diff --git a/lib/license/management/loggable.rb b/lib/license/management/loggable.rb new file mode 100644 index 0000000..a44d45d --- /dev/null +++ b/lib/license/management/loggable.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module License + module Management + module Loggable + def logger + ::LicenseFinder::Core.default_logger + end + + def log_info(message) + logger.info(self.class, message) + end + end + end +end diff --git a/lib/license/management/report.rb b/lib/license/management/report.rb new file mode 100644 index 0000000..5ac41bb --- /dev/null +++ b/lib/license/management/report.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'license/management/report/base' +require 'license/management/report/v1' + +module License + module Management + module Report + DEFAULT_VERSION = '1' + VERSIONS = { + nil => V1, + '' => V1, + '1' => V1, + '1.0' => V1 + }.freeze + + # This method overrides the method defined in `LicenseFinder::JsonReport` to + # allow us to generate a custom json report. + def to_s + JSON.pretty_generate(version_for(report_version).to_h) + "\n" + end + + private + + def report_version + ENV.fetch('LM_REPORT_VERSION', DEFAULT_VERSION) + end + + def version_for(version) + VERSIONS.fetch(version.to_s).new(dependencies) + end + end + end +end diff --git a/lib/license/management/report/base.rb b/lib/license/management/report/base.rb new file mode 100644 index 0000000..ab9b6a1 --- /dev/null +++ b/lib/license/management/report/base.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +module License + module Management + module Report + class Base + include Loggable + include Verifiable + + attr_reader :dependencies, :repository + + def initialize(dependencies) + @dependencies = dependencies + @repository = License::Management::Repository.new + end + + def to_h + raise NotImplementedError + end + + private + + def paths_from(dependency) + return [] unless dependency.respond_to?(:aggregate_paths) + + paths = dependency.aggregate_paths + return [] if blank?(paths) + + paths.map { |x| x.gsub(Dir.pwd, '.') } + end + + def description_for(dependency) + present?(dependency.summary) ? dependency.summary : dependency.description + end + end + end + end +end diff --git a/lib/license/management/report/v1.rb b/lib/license/management/report/v1.rb new file mode 100644 index 0000000..5882f72 --- /dev/null +++ b/lib/license/management/report/v1.rb @@ -0,0 +1,84 @@ +# 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 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 + .sort_by(&:name) + .map { |x| map_from_dependency(x) } + end + + def best_name_for(license) + license_data(license)['name'] + end + + def license_data(license) + return repository.item_for(license) if canonicalize? + + { + 'name' => license.name.split(/[\r\n]+/)[0], + 'url' => license.url + } + end + + def canonicalize? + ENV.fetch('LM_V1_CANONICALIZE', 'false') == 'true' + end + end + end + end +end diff --git a/lib/license/management/repository.rb b/lib/license/management/repository.rb new file mode 100644 index 0000000..2eee1b6 --- /dev/null +++ b/lib/license/management/repository.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +module License + module Management + class Repository + include Loggable + include Verifiable + + def initialize( + compatibility_path: License::Management.root.join('normalized-licenses.yml') + ) + @compatibility_data = YAML.safe_load(IO.read(compatibility_path)) + end + + def item_for(license) + id = id_for(license) + item = id ? compatibility_data['licenses'][id] : nil + item ? { 'id' => id }.merge(item) : generate_item_for(license) + end + + private + + attr_reader :compatibility_data + + def id_for(license) + ids = compatibility_data['ids'] + ids[license.send(:short_name)] || ids[license.url] + end + + # When `license_finder` is unable to determine the license it will use the full + # content of the file as the name of the license. This method shrinks that name + # down to just take the first line of the file. + def take_first_line_from(content) + return '' if blank?(content) + + content.split(/[\r\n]+/)[0] + end + + def generate_item_for(license) + log_info("detected unknown license named `#{license.send(:short_name)}`") + { + 'id' => 'unknown', + 'name' => take_first_line_from(license.name), + 'url' => present?(license.url) ? license.url : '' + } + end + end + end +end diff --git a/lib/license/management/verifiable.rb b/lib/license/management/verifiable.rb new file mode 100644 index 0000000..72667fb --- /dev/null +++ b/lib/license/management/verifiable.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module License + module Management + module Verifiable + def blank?(item) + item.nil? || item.empty? + end + + def present?(item) + !blank?(item) + end + end + end +end diff --git a/lib/license/management/version.rb b/lib/license/management/version.rb new file mode 100644 index 0000000..7fec52d --- /dev/null +++ b/lib/license/management/version.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module License + module Management + VERSION = '1.7.0' + end +end diff --git a/license-management.gemspec b/license-management.gemspec new file mode 100644 index 0000000..a4b6daa --- /dev/null +++ b/license-management.gemspec @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +lib = File.expand_path('lib', __dir__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'license/management/version' + +Gem::Specification.new do |spec| + spec.name = 'license-management' + spec.version = License::Management::VERSION + spec.authors = ['Fabien Catteau', 'Olivier Gonzalez', 'mo khan'] + spec.email = ['fcatteau@gitlab.com', 'ogonzalez@gitlab.com', 'mkhan@gitlab.com'] + + spec.summary = 'License Management job for GitLab CI.' + spec.description = 'License Management job for GitLab CI.' + spec.homepage = 'https://gitlab.com/gitlab-org/security-products/license-management' + spec.license = 'GitLab EE' + + spec.metadata['allowed_push_host'] = 'https://example.com' + spec.metadata['homepage_uri'] = spec.homepage + spec.metadata['source_code_uri'] = 'https://gitlab.com/gitlab-org/security-products/license-management' + spec.metadata['changelog_uri'] = 'https://gitlab.com/gitlab-org/security-products/license-management/blob/master/CHANGELOG.md' + + spec.files = Dir.chdir(File.expand_path(__dir__)) do + Dir.glob('exe/*') + Dir.glob('lib/**/**/*.{rb,yml}') + Dir.glob('*.{md,yml,json}') + end + spec.bindir = 'exe' + spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.require_paths = ['lib'] + + spec.add_dependency 'license_finder', ENV.fetch('LICENSE_FINDER_VERSION', '5.6.2') +end diff --git a/normalized-licenses.yml b/normalized-licenses.yml new file mode 100644 index 0000000..e26df4f --- /dev/null +++ b/normalized-licenses.yml @@ -0,0 +1,82 @@ +--- +ids: + ASL, version 2: Apache-2.0 + Apache1_1: Apache-1.1 + Apache2: Apache-2.0 + Apache 2.0: Apache-2.0 + BSD: BSD-4-Clause + CC01: CC0-1.0 + EPL1: EPL-1.0 + GPLv2: GPL-2.0 + GPLv3: GPL-3.0 + ISC: ISC + LGPL 2.1: LGPL-2.1 + LGPL, version 2.1: LGPL-2.1 + LGPL2_1: LGPL-2.1 + LGPL: LGPL-3.0-only + MIT: MIT + MPL 1.1: MPL-1.1 + MPL1_1: MPL-1.1 + MPL2: MPL-2.0 + New BSD License: BSD-3-Clause + NewBSD: BSD-3-Clause + Python: Python-2.0 + Ruby: Ruby + SimplifiedBSD: BSD-2-Clause + http://www.apache.org/licenses/LICENSE-2.0: Apache-2.0 + unknown: unknown +licenses: + GPL-3.0: + name: GPL 3.0 + url: https://www.gnu.org/licenses/gpl-3.0.txt + BSD-2-Clause: + name: Simplified BSD + url: https://opensource.org/licenses/bsd-license + ISC: + name: ISC + url: https://en.wikipedia.org/wiki/ISC_license + Apache-1.1: + name: Apache 1.1 + url: https://www.apache.org/licenses/LICENSE-1.1.txt + MPL-2.0: + name: Mozilla Public License 2.0 + url: https://www.mozilla.org/media/MPL/2.0/index.815ca599c9df.txt + LGPL-3.0-only: + name: LGPL + url: https://www.gnu.org/licenses/lgpl.txt + CC0-1.0: + name: CC0 1.0 + url: https://creativecommons.org/publicdomain/zero/1.0/ + unknown: + name: unknown + url: '' + GPL-2.0: + name: GPL 2.0 + url: https://www.gnu.org/licenses/gpl-2.0.txt + EPL-1.0: + name: EPL 1.0 + url: https://www.eclipse.org/legal/epl-v10.html + Python-2.0: + name: Python Software Foundation License + url: https://hg.python.org/cpython/raw-file/89ce323357db/LICENSE + BSD-3-Clause: + name: New BSD License + url: https://opensource.org/licenses/BSD-3-Clause + MIT: + name: MIT + url: https://opensource.org/licenses/mit-license + LGPL-2.1: + name: LGPL 2.1 + url: https://opensource.org/licenses/LGPL-2.1 + Ruby: + name: Ruby + url: https://www.ruby-lang.org/en/about/license.txt + Apache-2.0: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.txt + MPL-1.1: + name: MPL 1.1 + url: https://www.mozilla.org/en-US/MPL/1.1/ + BSD-4-Clause: + name: BSD + url: https://en.wikipedia.org/wiki/BSD_licenses#4-clause_license_.28original_.22BSD_License.22.29 @@ -115,12 +115,13 @@ case "$COMMAND" in gem install bundler # We need to install the license_finder gem into this Ruby version too. gem install license_finder -v "$LICENSE_FINDER_VERSION" + gem install --no-document /opt/license-management/*.gem fi # Ignore test and development dependencies. license_finder ignored_groups add development license_finder ignored_groups add test - bundle install --without "development test" + bundle install --without "development test" --jobs $(nproc) skip_prepare=true fi @@ -189,17 +190,24 @@ case "$COMMAND" in # Run License Finder. echo "Running license_finder $@ in $PWD" - if [ "$skip_prepare" != true ]; then prepare="--prepare" fi - license_finder report ${prepare} --format=html --save=gl-license-management-report.html + if [ "$FEATURE_RUBY_REPORT" = 'true' ]; then + echo "Preparing JSON report..." + license_management report ${prepare} --format=json --save=gl-license-management-report.json + else + echo "Preparing HTML report..." + license_finder report ${prepare} --format=html --save=gl-license-management-report.html + fi # rvm removes trap in bash: https://github.com/rvm/rvm/issues/4416 declare -f restore_lockfile > /dev/null && restore_lockfile popd > /dev/null - # Extract data from the HTML report and put it into a JSON file - node /html2json.js $APP_PATH/gl-license-management-report.html > $APP_PATH/gl-license-management-report.json + if [ -f "gl-license-management-report.html" ]; then + # Extract data from the HTML report and put it into a JSON file + node /html2json.js $APP_PATH/gl-license-management-report.html > $APP_PATH/gl-license-management-report.json + fi ;; *) diff --git a/test/results/go-modules.json b/test/results/go-modules-v1.json index b946b60..b946b60 100644 --- a/test/results/go-modules.json +++ b/test/results/go-modules-v1.json diff --git a/test/results/java-maven.json b/test/results/java-maven-v1.json index 58e9260..58e9260 100644 --- a/test/results/java-maven.json +++ b/test/results/java-maven-v1.json diff --git a/test/results/python-pip.json b/test/results/python-pip-v1.json index 3aa6f39..3aa6f39 100644 --- a/test/results/python-pip.json +++ b/test/results/python-pip-v1.json diff --git a/test/results/python3-pip.json b/test/results/python3-pip-v1.json index d98669d..d98669d 100644 --- a/test/results/python3-pip.json +++ b/test/results/python3-pip-v1.json diff --git a/test/results/ruby-bundler.json b/test/results/ruby-bundler-v1.json index c66a9a3..c66a9a3 100644 --- a/test/results/ruby-bundler.json +++ b/test/results/ruby-bundler-v1.json |
