Skip to content

Commit

Permalink
Merge pull request #891 from pivotal/yarn_licenses
Browse files Browse the repository at this point in the history
Support yarn licenses command in yarn v2+
  • Loading branch information
julia-pu authored Mar 16, 2022
2 parents 829fab0 + fadc9f6 commit ed3b319
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 27 deletions.
41 changes: 26 additions & 15 deletions lib/license_finder/package_managers/yarn.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@

module LicenseFinder
class Yarn < PackageManager
SHELL_COMMAND = 'yarn licenses list --no-progress --json'
SHELL_COMMAND = 'yarn licenses list --json'

def possible_package_paths
[project_path.join('yarn.lock')]
end

def current_packages
cmd = "#{Yarn::SHELL_COMMAND}#{yarn1_production_flag}"
suffix = " --cwd #{project_path}" unless project_path.nil?
cmd += suffix unless suffix.nil?
# the licenses plugin supports the classic production flag
cmd = "#{Yarn::SHELL_COMMAND}#{classic_yarn_production_flag}"
if yarn_version == 1
cmd += ' --no-progress'
cmd += " --cwd #{project_path}" unless project_path.nil?
end

stdout, stderr, status = Cmd.run(cmd)
raise "Command '#{cmd}' failed to execute: #{stderr}" unless status.success?
Expand Down Expand Up @@ -56,30 +59,38 @@ def package_management_command
end

def prepare_command
if yarn2_project?
yarn2_prepare_command
if yarn_version == 1
classic_yarn_prepare_command
else
yarn1_prepare_command
yarn_prepare_command
end
end

private

def yarn2_prepare_command
"#{yarn2_production_flag}yarn install"
def yarn_prepare_command
"#{yarn_plugin_production_command}yarn install && yarn plugin import https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/#{yarn_licenses_plugin_version}/bundles/@yarnpkg/plugin-licenses.js"
end

def classic_yarn_prepare_command
"yarn install --ignore-engines --ignore-scripts#{classic_yarn_production_flag}"
end

def yarn1_prepare_command
"yarn install --ignore-engines --ignore-scripts#{yarn1_production_flag}"
def yarn_licenses_plugin_version
if yarn_version == 2
'v0.6.0'
else
'v0.7.2'
end
end

def yarn2_project?
def yarn_version
Dir.chdir(project_path) do
version_string, stderr_str, status = Cmd.run('yarn -v')
raise "Command 'yarn -v' failed to execute: #{stderr_str}" unless status.success?

version = version_string.split('.').map(&:to_i)
return version[0] >= 2
return version[0]
end
end

Expand Down Expand Up @@ -120,13 +131,13 @@ def filter_yarn_internal_package(all_packages)
all_packages - [yarn_internal_package]
end

def yarn1_production_flag
def classic_yarn_production_flag
return '' if @ignored_groups.nil?

@ignored_groups.include?('devDependencies') ? ' --production' : ''
end

def yarn2_production_flag
def yarn_plugin_production_command
return '' if @ignored_groups.nil?

@ignored_groups.include?('devDependencies') ? 'yarn plugin import workspace-tools && yarn workspaces focus --all --production && ' : ''
Expand Down
87 changes: 75 additions & 12 deletions spec/lib/license_finder/package_managers/yarn_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ module LicenseFinder
end
end

context 'when using Yarn 2.x+ projects' do
context 'when using Yarn 3.x+ projects' do
before do
allow(SharedHelpers::Cmd).to receive(:run).with('yarn -v').and_return(['3.0.1', '', cmd_success])
end

it 'should call yarn install with no cli parameters' do
expect(SharedHelpers::Cmd).to receive(:run).with('yarn install')
expect(SharedHelpers::Cmd).to receive(:run).with('yarn install && yarn plugin import https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/v0.7.2/bundles/@yarnpkg/plugin-licenses.js')
.and_return([yarn_shell_command_output, '', cmd_success])
subject.prepare
end
Expand All @@ -64,22 +64,74 @@ module LicenseFinder
subject { Yarn.new(project_path: Pathname(root), ignored_groups: 'devDependencies') }

it 'should include a production flag' do
expect(SharedHelpers::Cmd).to receive(:run).with('yarn plugin import workspace-tools && yarn workspaces focus --all --production && yarn install')
expect(SharedHelpers::Cmd).to receive(:run).with('yarn plugin import workspace-tools && yarn workspaces focus --all --production && yarn install && yarn plugin import https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/v0.7.2/bundles/@yarnpkg/plugin-licenses.js')
.and_return([yarn_shell_command_output, '', cmd_success])
subject.prepare
end
end
end

context 'when using Yarn 2.x projects' do
before do
allow(SharedHelpers::Cmd).to receive(:run).with('yarn -v').and_return(['2.0.1', '', cmd_success])
end

it 'should call yarn install with no cli parameters' do
expect(SharedHelpers::Cmd).to receive(:run).with('yarn install && yarn plugin import https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/v0.6.0/bundles/@yarnpkg/plugin-licenses.js')
.and_return([yarn_shell_command_output, '', cmd_success])
subject.prepare
end

context 'ignored_groups contains devDependencies' do
subject { Yarn.new(project_path: Pathname(root), ignored_groups: 'devDependencies') }

it 'should include a production flag' do
expect(SharedHelpers::Cmd).to receive(:run).with('yarn plugin import workspace-tools && yarn workspaces focus --all --production && yarn install && yarn plugin import https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/v0.6.0/bundles/@yarnpkg/plugin-licenses.js')
.and_return([yarn_shell_command_output, '', cmd_success])
subject.prepare
end
end
end
end

describe '#current_packages' do
subject { Yarn.new(project_path: Pathname(root), logger: double(:logger, active: nil)) }

include FakeFS::SpecHelpers
before do
FileUtils.mkdir_p(Dir.tmpdir)
FileUtils.mkdir_p(root)
allow(SharedHelpers::Cmd).to receive(:run).with('yarn -v').and_return(['1.0.1', '', cmd_success])
end

context 'when using Yarn v2.x+' do
before do
allow(SharedHelpers::Cmd).to receive(:run).with('yarn -v').and_return(['2.0.1', '', cmd_success])
end

it 'should call licenses plugin and displays packages' do
allow(SharedHelpers::Cmd).to receive(:run).with('yarn config get modules-folder') do
["yarn_modules\n", '', cmd_success]
end
allow(SharedHelpers::Cmd).to receive(:run).with(Yarn::SHELL_COMMAND) do
[yarn_shell_command_output, '', cmd_success]
end

expect(subject.current_packages.length).to eq 1
expect(subject.current_packages.first.name).to eq 'yn'
expect(subject.current_packages.first.version).to eq '2.0.0'
expect(subject.current_packages.first.license_names_from_spec).to eq ['MIT']
expect(subject.current_packages.first.homepage).to eq 'sindresorhus.com'
expect(subject.current_packages.first.authors).to eq 'Sindre Sorhus'
expect(subject.current_packages.first.install_path).to eq Pathname(root).join('yarn_modules', 'yn')
end
end

it 'displays packages as returned from "yarn list"' do
allow(SharedHelpers::Cmd).to receive(:run).with('yarn config get modules-folder') do
["yarn_modules\n", '', cmd_success]
end
allow(SharedHelpers::Cmd).to receive(:run).with(Yarn::SHELL_COMMAND + " --cwd #{Pathname(root)}") do
allow(SharedHelpers::Cmd).to receive(:run).with(Yarn::SHELL_COMMAND + " --no-progress --cwd #{Pathname(root)}") do
[yarn_shell_command_output, '', cmd_success]
end

Expand All @@ -96,15 +148,15 @@ module LicenseFinder
allow(SharedHelpers::Cmd).to receive(:run).with('yarn config get modules-folder') do
["undefined\n", '', cmd_success]
end
allow(SharedHelpers::Cmd).to receive(:run).with(Yarn::SHELL_COMMAND + " --cwd #{Pathname(root)}") do
allow(SharedHelpers::Cmd).to receive(:run).with(Yarn::SHELL_COMMAND + " --no-progress --cwd #{Pathname(root)}") do
[yarn_shell_command_output, '', cmd_success]
end

expect(subject.current_packages.first.install_path).to eq Pathname(root).join('node_modules', 'yn')
end

it 'displays incompatible packages with license type unknown' do
allow(SharedHelpers::Cmd).to receive(:run).with(Yarn::SHELL_COMMAND + " --cwd #{Pathname(root)}") do
allow(SharedHelpers::Cmd).to receive(:run).with(Yarn::SHELL_COMMAND + " --no-progress --cwd #{Pathname(root)}") do
['{"type":"info","data":"[email protected]: The platform \"linux\" is incompatible with this module."}
{"type":"info","data":"\"[email protected]\" is an optional dependency and failed compatibility check. Excluding it from installation."}', '', cmd_success]
end
Expand All @@ -119,7 +171,7 @@ module LicenseFinder
allow(SharedHelpers::Cmd).to receive(:run).with('yarn config get modules-folder') do
['yarn_modules', '', cmd_success]
end
allow(SharedHelpers::Cmd).to receive(:run).with(Yarn::SHELL_COMMAND + " --cwd #{Pathname(root)}") do
allow(SharedHelpers::Cmd).to receive(:run).with(Yarn::SHELL_COMMAND + " --no-progress --cwd #{Pathname(root)}") do
[{
'type' => 'table',
'data' => {
Expand All @@ -141,7 +193,7 @@ module LicenseFinder
it 'should include a production flag' do
expect(SharedHelpers::Cmd).to receive(:run).with('yarn config get modules-folder')
.and_return(['yarn_modules', '', cmd_success])
expect(SharedHelpers::Cmd).to receive(:run).with("#{Yarn::SHELL_COMMAND} --production --cwd #{Pathname(root)}")
expect(SharedHelpers::Cmd).to receive(:run).with("#{Yarn::SHELL_COMMAND} --production --no-progress --cwd #{Pathname(root)}")
.and_return([yarn_shell_command_output, '', cmd_success])
subject.current_packages
end
Expand All @@ -152,7 +204,7 @@ module LicenseFinder
allow(SharedHelpers::Cmd).to receive(:run).with('yarn config get modules-folder') do
['yarn_modules', '', cmd_success]
end
allow(SharedHelpers::Cmd).to receive(:run).with(Yarn::SHELL_COMMAND + " --cwd #{Pathname(root)}") do
allow(SharedHelpers::Cmd).to receive(:run).with(Yarn::SHELL_COMMAND + " --no-progress --cwd #{Pathname(root)}") do
[{
'type' => 'table',
'data' => {
Expand All @@ -173,9 +225,9 @@ module LicenseFinder

context 'when the shell command fails' do
it 'an error is raised' do
allow(SharedHelpers::Cmd).to receive(:run).with(Yarn::SHELL_COMMAND + " --cwd #{Pathname(root)}").and_return([nil, 'error', cmd_failure])
allow(SharedHelpers::Cmd).to receive(:run).with(Yarn::SHELL_COMMAND + " --no-progress --cwd #{Pathname(root)}").and_return([nil, 'error', cmd_failure])

expect { subject.current_packages }.to raise_error(/Command 'yarn licenses list --no-progress --json --cwd #{Pathname(root)}' failed to execute: error/)
expect { subject.current_packages }.to raise_error(/Command 'yarn licenses list --json --no-progress --cwd #{Pathname(root)}' failed to execute: error/)
end
end
end
Expand All @@ -199,13 +251,24 @@ module LicenseFinder
end

context 'when in a Yarn 2.x project' do
before do
allow(SharedHelpers::Cmd).to receive(:run).with('yarn -v').and_return(['2.1.9', '', cmd_success])
end

subject { Yarn.new(project_path: Pathname(root), logger: double(:logger, active: nil)) }
it 'returns the correct prepare method' do
expect(subject.prepare_command).to eq('yarn install && yarn plugin import https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/v0.6.0/bundles/@yarnpkg/plugin-licenses.js')
end
end

context 'when in a Yarn 3.x+ project' do
before do
allow(SharedHelpers::Cmd).to receive(:run).with('yarn -v').and_return(['3.5.9', '', cmd_success])
end

subject { Yarn.new(project_path: Pathname(root), logger: double(:logger, active: nil)) }
it 'returns the correct prepare method' do
expect(subject.prepare_command).to eq('yarn install')
expect(subject.prepare_command).to eq('yarn install && yarn plugin import https://raw.githubusercontent.com/mhassan1/yarn-plugin-licenses/v0.7.2/bundles/@yarnpkg/plugin-licenses.js')
end
end
end
Expand Down

0 comments on commit ed3b319

Please sign in to comment.