add migrate command, migrate to v2

This commit is contained in:
Jon Ruskin 2019-02-09 00:33:08 -07:00
Родитель 4b3ea99d8b
Коммит ea44e0cbc2
11 изменённых файлов: 193 добавлений и 0 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -23,6 +23,7 @@ test/fixtures/cabal/*
!test/fixtures/cabal/app*
test/fixtures/git_submodule/*
!test/fixtures/git_submodule/README
!test/fixtures/migrations/**/*
vendor/licenses
.licenses

Просмотреть файл

@ -12,6 +12,12 @@ Licensed is **not** a complete open source license compliance solution. Please u
Licensed is in active development and currently used at GitHub. See the [open issues](https://github.com/github/licensed/issues) for a list of potential work.
## Migrating to 2.x
Licensed 2.x is incompatible with configuration files and cached records from 1.x. Migrating to 2.x is easy using the `licensed migrate` command.
See the [migration documentation](./docs/migrating_to_newer_versions.md) for more info, or run `licensed help migrate`.
## Installation
### With a Gemfile

Просмотреть файл

@ -0,0 +1,3 @@
# Migrating your licensed configuration and cached records to the latest version of licensed
Licensed v2+ ships with an additional executable, `licensed-migrator`, that can be used to update your licensed files to the format expected by the currently installed version. To run, execute `licensed migrate --from v1 -c <path to licensed configuration file>`, replacing `v1` with the major version of licensed to migrate from.

Просмотреть файл

@ -9,3 +9,4 @@ require "licensed/configuration"
require "licensed/reporters"
require "licensed/commands"
require "licensed/ui/shell"
require "licensed/migrations"

Просмотреть файл

@ -35,6 +35,23 @@ module Licensed
puts Licensed::VERSION
end
desc "migrate", "Migrate from a previous version of licensed"
method_option :config, aliases: "-c", type: :string, required: true,
desc: "Path to licensed configuration file"
method_option :from, aliases: "-f", type: :string, required: true,
desc: "Licensed version to migrate from - #{Licensed.previous_major_versions.map { |major| "v#{major}" }.join(", ")}"
def migrate
case options["from"]
when "v1"
Licensed::Migrations::V2.migrate(options["config"], shell)
else
shell = Thor::Base.shell.new
shell.say "Unrecognized option from=#{options["from"]}", :red
CLI.command_help(shell, 'migrate')
exit 1
end
end
# If an error occurs (e.g. a missing command or argument), exit 1.
def self.exit_on_failure?
true

Просмотреть файл

@ -0,0 +1,7 @@
# frozen_string_literal: true
module Licensed
module Migrations
require "licensed/migrations/v2"
end
end

Просмотреть файл

@ -0,0 +1,47 @@
# frozen_string_literal: true
require "licensed/shell"
module Licensed
module Migrations
class V2
def self.migrate(config_path, shell = Licensed::UI::Shell.new)
shell.info "updating to v2"
shell.info "updating bundler configuration keys"
# replace all "rubygem" and "rubygems" configuration keys with "bundler"
# to account for the bundler source's `type` change from `rubygem` to `bundler`
File.write(config_path, File.read(config_path).gsub(/rubygems?:/, "bundler:"))
shell.info "updating cached records"
# load the configuration to find and update cached contents
configuration = Licensed::Configuration.load_from(config_path)
configuration.apps.each do |app|
Dir.chdir app.cache_path do
# licensed v1 cached records were stored as .txt files with YAML frontmatter
Dir["**/*.txt"].each do |file|
# find the yaml and non-yaml data by parsing the yaml data out of the contents
# then reserializing the contents to a string that can be stripped from the
# original file contents
cached_contents = File.read(file)
yaml = YAML.load(cached_contents)
cached_contents = cached_contents.gsub(yaml.to_yaml + "---", "")
# in v1, licenses and notices are separated by special text dividers
# in v2, cached records are defined and formatted entirely in yaml
licenses, *notices = cached_contents.split(("-") * 80).map(&:strip)
licenses = licenses.split(("*") * 80).map(&:strip)
yaml["licenses"] = licenses.map { |text| { "text" => text } }
yaml["notices"] = notices.map { |text| { "text" => text } }
# v2 records are stored in `.dep.yml` files
# write the new yaml contents to the new file and delete old file
new_file = file.gsub(".txt", ".dep.yml")
File.write(new_file, yaml.to_yaml)
File.delete(file)
end
end
end
end
end
end
end

Просмотреть файл

@ -1,4 +1,9 @@
# frozen_string_literal: true
module Licensed
VERSION = "1.5.2".freeze
def self.previous_major_versions
major_version = Gem::Version.new(Licensed::VERSION).segments.first
(1...major_version).to_a
end
end

23
test/fixtures/migrations/v2/.licensed.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,23 @@
name: migration-v2
cache_path: cache
sources:
rubygem: true
reviewed:
rubygem:
- test
ignored:
rubygem:
- test
rubygem:
value: test
apps:
- source_path: "."
- source_path: "."
reviewed:
rubygem: # to verify that individual app configurations are updated as well
- test

43
test/fixtures/migrations/v2/cache/manifest/notices.txt поставляемый Normal file
Просмотреть файл

@ -0,0 +1,43 @@
---
type: manifest
name: notices
version: bd72e775440b11efdea627789f1d92ca3bcfd772
license: bsd-3-clause
---
Copyright 2018 GitHub
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
--------------------------------------------------------------------------------
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum sed mollis
magna. Integer vehicula condimentum justo, a ornare urna congue sit amet.
Nulla quis hendrerit metus, eu iaculis dui. Integer vitae turpis sapien.
Maecenas sed ultrices mauris. Nunc posuere dictum malesuada. Cras sapien eros,
pulvinar vitae orci sed, euismod pretium lectus. Sed varius sodales dui, quis
lobortis turpis elementum in. Vestibulum accumsan lectus eget ipsum rutrum,
quis malesuada elit euismod. Proin porta sem posuere tempor gravida. Duis
lacinia diam in neque faucibus, sed egestas erat suscipit. Aenean blandit diam
sem.

Просмотреть файл

@ -0,0 +1,40 @@
# frozen_string_literal: true
require "test_helper"
describe Licensed::Migrations::V2 do
let(:fixtures) { File.expand_path("../../fixtures/migrations/v2", __FILE__) }
let(:shell) { TestShell.new }
it "updates configuration settings" do
Dir.mktmpdir do |tmp|
FileUtils.cp_r fixtures, tmp
Dir.chdir(File.join(tmp, "v2")) do
Licensed::Migrations::V2.migrate(".licensed.yml", shell)
configuration = Licensed::Configuration.load_from(".licensed.yml")
configuration.apps.each do |app|
assert app.enabled?("bundler")
refute app.enabled?("rubygem")
assert app.reviewed?({ "name" => "test", "type" => "bundler" })
refute app.reviewed?({ "name" => "test", "type" => "rubygem" })
assert app.ignored?({ "name" => "test", "type" => "bundler" })
refute app.ignored?({ "name" => "test", "type" => "rubygem" })
assert_equal "test", app.dig("bundler", "value")
assert_nil app.dig("rubygem", "value")
end
end
end
end
it "updates cached records" do
Dir.mktmpdir do |tmp|
FileUtils.cp_r fixtures, tmp
Dir.chdir(File.join(tmp, "v2")) do
Licensed::Migrations::V2.migrate(".licensed.yml", shell)
cached_record = Licensed::DependencyRecord.read("cache/manifest/notices.dep.yml")
assert cached_record
refute_empty cached_record.licenses
refute_empty cached_record.notices
end
end
end
end