Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add pnpm source for dependency enumeration #626

Merged
merged 2 commits into from
Feb 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,45 @@ jobs:
- name: Run tests
run: script/test pipenv

pnpm:
runs-on: ubuntu-latest
needs: core
strategy:
matrix:
pnpm_version: [ 7 ]
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2
name: Install pnpm
id: pnpm-install
with:
version: ${{ matrix.pnpm_version }}
run_install: false

- name: Get pnpm store directory
id: pnpm-cache
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT

- uses: actions/cache@v3
name: Setup pnpm cache
with:
path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true

- name: Set up fixtures
run: script/source-setup/pnpm
- name: Run tests
run: script/test pnpm

swift:
runs-on: ubuntu-20.04
needs: core
Expand Down
18 changes: 18 additions & 0 deletions docs/sources/pnpm.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# pnpm

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.

**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).

## Including development dependencies

By default, the npm source will exclude all development dependencies. To include development or test dependencies, set `production_only: false` in the licensed configuration.

```yml
pnpm:
production_only: false
```

## Using licensed with pnpm workspaces

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.
7 changes: 4 additions & 3 deletions lib/licensed/sources.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,20 @@ module Sources
require "licensed/sources/bundler"
require "licensed/sources/cabal"
require "licensed/sources/cargo"
require "licensed/sources/cocoapods"
require "licensed/sources/composer"
require "licensed/sources/dep"
require "licensed/sources/git_submodule"
require "licensed/sources/go"
require "licensed/sources/gradle"
require "licensed/sources/manifest"
require "licensed/sources/mix"
require "licensed/sources/npm"
require "licensed/sources/nuget"
require "licensed/sources/pip"
require "licensed/sources/pipenv"
require "licensed/sources/pnpm"
require "licensed/sources/swift"
require "licensed/sources/gradle"
require "licensed/sources/mix"
require "licensed/sources/yarn"
require "licensed/sources/cocoapods"
end
end
52 changes: 52 additions & 0 deletions lib/licensed/sources/pnpm.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# frozen_string_literal: true
require "json"

module Licensed
module Sources
class PNPM < Source
# Returns true when pnpm is installed and a pnpm-lock.yaml file is found,
# otherwise false
def enabled?
return false unless Licensed::Shell.tool_available?("pnpm")
File.exist?(File.join(config.pwd, "pnpm-lock.yaml"))
end

def enumerate_dependencies
packages.map do |package|
name_with_version = "#{package["name"]}@#{package["version"]}"
Dependency.new(
name: name_with_version,
version: package["version"],
path: package["path"],
metadata: {
"type" => PNPM.type,
"name" => package["name"],
"summary" => package["description"],
"homepage" => package["homepage"]
}
)
end
end

# Returns package metadata returned from `pnpm licensed list`
def packages
JSON.parse(package_metadata_command).values.flatten
rescue JSON::ParserError => e
message = "Licensed was unable to parse the output from 'pnpm licenses list'. JSON Error: #{e.message}"
raise Licensed::Sources::Source::Error, message
end

# Returns the output from running `pnpm licenses list` to get package metadata
def package_metadata_command
args = %w(--json --long)
args << "--prod" unless include_non_production?
Licensed::Shell.execute("pnpm", "licenses", "list", *args, allow_failure: true)
end

# Returns whether to include non production dependencies based on the licensed configuration settings
def include_non_production?
config.dig("pnpm", "production_only") == false
end
end
end
end
17 changes: 17 additions & 0 deletions script/source-setup/pnpm
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash
set -e

if [ -z "$(which pnpm)" ]; then
echo "A local pnpm installation is required for pnpm development." >&2
exit 127
fi

# setup test fixtures
BASE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd $BASE_PATH/test/fixtures/pnpm

if [ "$1" == "-f" ]; then
git clean -ffX .
fi

pnpm install --shamefully-hoist
1 change: 1 addition & 0 deletions test/fixtures/pnpm/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
5 changes: 5 additions & 0 deletions test/fixtures/pnpm/.licensed.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
expected_dependency: autoprefixer@5.2.0
expected_dependency_name: autoprefixer
root: .
sources:
pnpm: true
17 changes: 17 additions & 0 deletions test/fixtures/pnpm/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "licensed-fixtures",
"version": "1.0.0",
"description": "pnpm test fixture",
"repository": "https://github.com/github/licensed",
"license": "MIT",
"dependencies": {
"@github/query-selector": "1.0.3",
"@optimizely/optimizely-sdk": "4.0.0",
"autoprefixer": "5.2.0",
"node-fetch": "2.6.7",
"@nestjs/core": "8.2.6"
},
"devDependencies": {
"string.prototype.startswith": "0.2.0"
}
}
10 changes: 10 additions & 0 deletions test/fixtures/pnpm/packages/a/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "licensed-fixtures-a",
"version": "1.0.0",
"description": "",
"author": "",
"license": "MIT",
"dependencies": {
"callbackify": "1.1.0"
}
}
Loading