Add licenses plugin (#118)
This commit is contained in:
@@ -16,12 +16,13 @@ RUN chmod +x /metrics/source/app/action/index.mjs \
|
|||||||
&& apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
|
&& apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
|
||||||
--no-install-recommends \
|
--no-install-recommends \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
# Install ruby to support linguist
|
# Install ruby to support github gems
|
||||||
# Based on https://github.com/github/linguist
|
# Based on https://github.com/github/linguist and https://github.com/github/licensed
|
||||||
&& apt-get update \
|
&& apt-get update \
|
||||||
&& apt-get install -y ruby-full \
|
&& apt-get install -y ruby-full \
|
||||||
&& apt-get install -y git g++ cmake pkg-config libicu-dev zlib1g-dev libcurl4-openssl-dev libssl-dev ruby-dev \
|
&& apt-get install -y git g++ cmake pkg-config libicu-dev zlib1g-dev libcurl4-openssl-dev libssl-dev ruby-dev \
|
||||||
&& gem install github-linguist \
|
&& gem install github-linguist \
|
||||||
|
&& gem install licensed \
|
||||||
# Install python for node-gyp
|
# Install python for node-gyp
|
||||||
&& apt-get update \
|
&& apt-get update \
|
||||||
&& apt-get install -y python3 \
|
&& apt-get install -y python3 \
|
||||||
|
|||||||
278
source/app/mocks/api/github/graphql/licenses.default.mjs
Normal file
278
source/app/mocks/api/github/graphql/licenses.default.mjs
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
/**Mocked data */
|
||||||
|
export default function({faker, query, login = faker.internet.userName()}) {
|
||||||
|
console.debug("metrics/compute/mocks > mocking graphql api result > licenses/default")
|
||||||
|
return ({
|
||||||
|
licenses:[
|
||||||
|
{
|
||||||
|
spdxId:"AGPL-3.0",
|
||||||
|
name:"GNU Affero General Public License v3.0",
|
||||||
|
nickname:"GNU AGPLv3",
|
||||||
|
key:"agpl-3.0",
|
||||||
|
limitations:[
|
||||||
|
{key:"liability", label:"Liability"},
|
||||||
|
{key:"warranty", label:"Warranty"},
|
||||||
|
],
|
||||||
|
conditions:[
|
||||||
|
{key:"include-copyright", label:"License and copyright notice"},
|
||||||
|
{key:"document-changes", label:"State changes"},
|
||||||
|
{key:"disclose-source", label:"Disclose source"},
|
||||||
|
{key:"network-use-disclose", label:"Network use is distribution"},
|
||||||
|
{key:"same-license", label:"Same license"},
|
||||||
|
],
|
||||||
|
permissions:[
|
||||||
|
{key:"commercial-use", label:"Commercial use"},
|
||||||
|
{key:"modifications", label:"Modification"},
|
||||||
|
{key:"distribution", label:"Distribution"},
|
||||||
|
{key:"patent-use", label:"Patent use"},
|
||||||
|
{key:"private-use", label:"Private use"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spdxId:"Apache-2.0",
|
||||||
|
name:"Apache License 2.0",
|
||||||
|
nickname:null,
|
||||||
|
key:"apache-2.0",
|
||||||
|
limitations:[
|
||||||
|
{key:"trademark-use", label:"Trademark use"},
|
||||||
|
{key:"liability", label:"Liability"},
|
||||||
|
{key:"warranty", label:"Warranty"},
|
||||||
|
],
|
||||||
|
conditions:[
|
||||||
|
{key:"include-copyright", label:"License and copyright notice"},
|
||||||
|
{key:"document-changes", label:"State changes"},
|
||||||
|
],
|
||||||
|
permissions:[
|
||||||
|
{key:"commercial-use", label:"Commercial use"},
|
||||||
|
{key:"modifications", label:"Modification"},
|
||||||
|
{key:"distribution", label:"Distribution"},
|
||||||
|
{key:"patent-use", label:"Patent use"},
|
||||||
|
{key:"private-use", label:"Private use"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spdxId:"BSD-2-Clause",
|
||||||
|
name:'BSD 2-Clause "Simplified" License',
|
||||||
|
nickname:null,
|
||||||
|
key:"bsd-2-clause",
|
||||||
|
limitations:[
|
||||||
|
{key:"liability", label:"Liability"},
|
||||||
|
{key:"warranty", label:"Warranty"},
|
||||||
|
],
|
||||||
|
conditions:[
|
||||||
|
{key:"include-copyright", label:"License and copyright notice"},
|
||||||
|
],
|
||||||
|
permissions:[
|
||||||
|
{key:"commercial-use", label:"Commercial use"},
|
||||||
|
{key:"modifications", label:"Modification"},
|
||||||
|
{key:"distribution", label:"Distribution"},
|
||||||
|
{key:"private-use", label:"Private use"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spdxId:"BSD-3-Clause",
|
||||||
|
name:'BSD 3-Clause "New" or "Revised" License',
|
||||||
|
nickname:null,
|
||||||
|
key:"bsd-3-clause",
|
||||||
|
limitations:[
|
||||||
|
{key:"liability", label:"Liability"},
|
||||||
|
{key:"warranty", label:"Warranty"},
|
||||||
|
],
|
||||||
|
conditions:[
|
||||||
|
{key:"include-copyright", label:"License and copyright notice"},
|
||||||
|
],
|
||||||
|
permissions:[
|
||||||
|
{key:"commercial-use", label:"Commercial use"},
|
||||||
|
{key:"modifications", label:"Modification"},
|
||||||
|
{key:"distribution", label:"Distribution"},
|
||||||
|
{key:"private-use", label:"Private use"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spdxId:"BSL-1.0",
|
||||||
|
name:"Boost Software License 1.0",
|
||||||
|
nickname:null,
|
||||||
|
key:"bsl-1.0",
|
||||||
|
limitations:[
|
||||||
|
{key:"liability", label:"Liability"},
|
||||||
|
{key:"warranty", label:"Warranty"},
|
||||||
|
],
|
||||||
|
conditions:[
|
||||||
|
{key:"include-copyright--source", label:"License and copyright notice for source"},
|
||||||
|
],
|
||||||
|
permissions:[
|
||||||
|
{key:"commercial-use", label:"Commercial use"},
|
||||||
|
{key:"modifications", label:"Modification"},
|
||||||
|
{key:"distribution", label:"Distribution"},
|
||||||
|
{key:"private-use", label:"Private use"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spdxId:"CC0-1.0",
|
||||||
|
name:"Creative Commons Zero v1.0 Universal",
|
||||||
|
nickname:null,
|
||||||
|
key:"cc0-1.0",
|
||||||
|
limitations:[
|
||||||
|
{key:"liability", label:"Liability"},
|
||||||
|
{key:"trademark-use", label:"Trademark use"},
|
||||||
|
{key:"patent-use", label:"Patent use"},
|
||||||
|
{key:"warranty", label:"Warranty"},
|
||||||
|
],
|
||||||
|
conditions:[],
|
||||||
|
permissions:[
|
||||||
|
{key:"commercial-use", label:"Commercial use"},
|
||||||
|
{key:"modifications", label:"Modification"},
|
||||||
|
{key:"distribution", label:"Distribution"},
|
||||||
|
{key:"private-use", label:"Private use"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spdxId:"EPL-2.0",
|
||||||
|
name:"Eclipse Public License 2.0",
|
||||||
|
nickname:null,
|
||||||
|
key:"epl-2.0",
|
||||||
|
limitations:[
|
||||||
|
{key:"liability", label:"Liability"},
|
||||||
|
{key:"warranty", label:"Warranty"},
|
||||||
|
],
|
||||||
|
conditions:[
|
||||||
|
{key:"disclose-source", label:"Disclose source"},
|
||||||
|
{key:"include-copyright", label:"License and copyright notice"},
|
||||||
|
{key:"same-license", label:"Same license"},
|
||||||
|
],
|
||||||
|
permissions:[
|
||||||
|
{key:"commercial-use", label:"Commercial use"},
|
||||||
|
{key:"distribution", label:"Distribution"},
|
||||||
|
{key:"modifications", label:"Modification"},
|
||||||
|
{key:"patent-use", label:"Patent use"},
|
||||||
|
{key:"private-use", label:"Private use"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spdxId:"GPL-2.0",
|
||||||
|
name:"GNU General Public License v2.0",
|
||||||
|
nickname:"GNU GPLv2",
|
||||||
|
key:"gpl-2.0",
|
||||||
|
limitations:[
|
||||||
|
{key:"liability", label:"Liability"},
|
||||||
|
{key:"warranty", label:"Warranty"},
|
||||||
|
],
|
||||||
|
conditions:[
|
||||||
|
{key:"include-copyright", label:"License and copyright notice"},
|
||||||
|
{key:"document-changes", label:"State changes"},
|
||||||
|
{key:"disclose-source", label:"Disclose source"},
|
||||||
|
{key:"same-license", label:"Same license"},
|
||||||
|
],
|
||||||
|
permissions:[
|
||||||
|
{key:"commercial-use", label:"Commercial use"},
|
||||||
|
{key:"modifications", label:"Modification"},
|
||||||
|
{key:"distribution", label:"Distribution"},
|
||||||
|
{key:"private-use", label:"Private use"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spdxId:"GPL-3.0",
|
||||||
|
name:"GNU General Public License v3.0",
|
||||||
|
nickname:"GNU GPLv3",
|
||||||
|
key:"gpl-3.0",
|
||||||
|
limitations:[
|
||||||
|
{key:"liability", label:"Liability"},
|
||||||
|
{key:"warranty", label:"Warranty"},
|
||||||
|
],
|
||||||
|
conditions:[
|
||||||
|
{key:"include-copyright", label:"License and copyright notice"},
|
||||||
|
{key:"document-changes", label:"State changes"},
|
||||||
|
{key:"disclose-source", label:"Disclose source"},
|
||||||
|
{key:"same-license", label:"Same license"},
|
||||||
|
],
|
||||||
|
permissions:[
|
||||||
|
{key:"commercial-use", label:"Commercial use"},
|
||||||
|
{key:"modifications", label:"Modification"},
|
||||||
|
{key:"distribution", label:"Distribution"},
|
||||||
|
{key:"patent-use", label:"Patent use"},
|
||||||
|
{key:"private-use", label:"Private use"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spdxId:"LGPL-2.1",
|
||||||
|
name:"GNU Lesser General Public License v2.1",
|
||||||
|
nickname:"GNU LGPLv2.1",
|
||||||
|
key:"lgpl-2.1",
|
||||||
|
limitations:[
|
||||||
|
{key:"liability", label:"Liability"},
|
||||||
|
{key:"warranty", label:"Warranty"},
|
||||||
|
],
|
||||||
|
conditions:[
|
||||||
|
{key:"include-copyright", label:"License and copyright notice"},
|
||||||
|
{key:"disclose-source", label:"Disclose source"},
|
||||||
|
{key:"document-changes", label:"State changes"},
|
||||||
|
{key:"same-license--library", label:"Same license (library)"},
|
||||||
|
],
|
||||||
|
permissions:[
|
||||||
|
{key:"commercial-use", label:"Commercial use"},
|
||||||
|
{key:"modifications", label:"Modification"},
|
||||||
|
{key:"distribution", label:"Distribution"},
|
||||||
|
{key:"private-use", label:"Private use"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spdxId:"MIT",
|
||||||
|
name:"MIT License",
|
||||||
|
nickname:null,
|
||||||
|
key:"mit",
|
||||||
|
limitations:[
|
||||||
|
{key:"liability", label:"Liability"},
|
||||||
|
{key:"warranty", label:"Warranty"},
|
||||||
|
],
|
||||||
|
conditions:[
|
||||||
|
{key:"include-copyright", label:"License and copyright notice"},
|
||||||
|
],
|
||||||
|
permissions:[
|
||||||
|
{key:"commercial-use", label:"Commercial use"},
|
||||||
|
{key:"modifications", label:"Modification"},
|
||||||
|
{key:"distribution", label:"Distribution"},
|
||||||
|
{key:"private-use", label:"Private use"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spdxId:"MPL-2.0",
|
||||||
|
name:"Mozilla Public License 2.0",
|
||||||
|
nickname:null,
|
||||||
|
key:"mpl-2.0",
|
||||||
|
limitations:[
|
||||||
|
{key:"liability", label:"Liability"},
|
||||||
|
{key:"trademark-use", label:"Trademark use"},
|
||||||
|
{key:"warranty", label:"Warranty"},
|
||||||
|
],
|
||||||
|
conditions:[
|
||||||
|
{key:"disclose-source", label:"Disclose source"},
|
||||||
|
{key:"include-copyright", label:"License and copyright notice"},
|
||||||
|
{key:"same-license--file", label:"Same license (file)"},
|
||||||
|
],
|
||||||
|
permissions:[
|
||||||
|
{key:"commercial-use", label:"Commercial use"},
|
||||||
|
{key:"modifications", label:"Modification"},
|
||||||
|
{key:"distribution", label:"Distribution"},
|
||||||
|
{key:"patent-use", label:"Patent use"},
|
||||||
|
{key:"private-use", label:"Private use"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
spdxId:"Unlicense",
|
||||||
|
name:"The Unlicense",
|
||||||
|
nickname:null,
|
||||||
|
key:"unlicense",
|
||||||
|
limitations:[
|
||||||
|
{key:"liability", label:"Liability"},
|
||||||
|
{key:"warranty", label:"Warranty"},
|
||||||
|
],
|
||||||
|
conditions:[],
|
||||||
|
permissions:[
|
||||||
|
{key:"private-use", label:"Private use"},
|
||||||
|
{key:"commercial-use", label:"Commercial use"},
|
||||||
|
{key:"modifications", label:"Modification"},
|
||||||
|
{key:"distribution", label:"Distribution"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
13
source/app/mocks/api/github/graphql/licenses.repository.mjs
Normal file
13
source/app/mocks/api/github/graphql/licenses.repository.mjs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/**Mocked data */
|
||||||
|
export default function({faker, query, login = faker.internet.userName()}) {
|
||||||
|
console.debug("metrics/compute/mocks > mocking graphql api result > licenses/repository")
|
||||||
|
return ({
|
||||||
|
user:{
|
||||||
|
repository:{
|
||||||
|
licenseInfo:{spdxId:"MIT", name:"MIT License", nickname:null, key:"mit"},
|
||||||
|
url:"https://github.com/lowlighter/metrics",
|
||||||
|
databaseId:293860197,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
37
source/plugins/licenses/README.md
Normal file
37
source/plugins/licenses/README.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
### 📜 Licenses
|
||||||
|
|
||||||
|
⚠️ This is NOT legal advice, use at your own risk
|
||||||
|
💣 Do NOT enable this plugin on public web instances (plugin allows raw commands injection)
|
||||||
|
|
||||||
|
The *licenses* plugin lets you display license informations like permissions, limitations and conditions along with additional metrics about dependencies.
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<td align="center">
|
||||||
|
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.licenses.svg">
|
||||||
|
<details open><summary>With licenses ratio</summary>
|
||||||
|
<img src="https://github.com/lowlighter/lowlighter/blob/master/metrics.plugin.licenses.ratio.svg">
|
||||||
|
</details>
|
||||||
|
<img width="900" height="1" alt="">
|
||||||
|
</td>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
Project must be setup with dependencies using `plugin_licenses_setup` option (for example, `npm ci` for a NodeJS project).
|
||||||
|
|
||||||
|
Dependencies will be analyzed with [github/licensed](https://github.com/github/licensed) and compared against GitHub known licenses.
|
||||||
|
|
||||||
|
#### ℹ️ Examples workflows
|
||||||
|
|
||||||
|
[➡️ Available options for this plugin](metadata.yml)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: lowlighter/metrics@latest
|
||||||
|
with:
|
||||||
|
# ... other options
|
||||||
|
template: repository
|
||||||
|
user: repository-owner
|
||||||
|
query: '{"repo":"repository-name"}'
|
||||||
|
plugin_licenses: yes
|
||||||
|
plugin_licenses_setup: npm ci # Command to setup target repository
|
||||||
|
plugin_licenses_ratio: yes # Display used licenses ratio
|
||||||
|
plugin_licenses_legal: yes # Display permissions, limitations and conditions
|
||||||
|
```
|
||||||
147
source/plugins/licenses/index.mjs
Normal file
147
source/plugins/licenses/index.mjs
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
//Setup
|
||||||
|
export default async function({login, q, imports, data, graphql, queries, account}, {enabled = false} = {}) {
|
||||||
|
//Plugin execution
|
||||||
|
try {
|
||||||
|
//Check if plugin is enabled and requirements are met
|
||||||
|
if ((!enabled)||(!q.licenses))
|
||||||
|
return null
|
||||||
|
|
||||||
|
//Load inputs
|
||||||
|
let {setup, ratio, legal} = imports.metadata.plugins.licenses.inputs({data, account, q})
|
||||||
|
|
||||||
|
//Initialization
|
||||||
|
const {user:{repository}} = await graphql(queries.licenses.repository({owner:data.repo.owner.login, name:data.repo.name, account}))
|
||||||
|
const result = {ratio, legal, default:repository.licenseInfo, licensed:{available:false}, text:{}, list:[], used:{}, dependencies:[], known:0, unknown:0}
|
||||||
|
const {used, text} = result
|
||||||
|
|
||||||
|
//Register existing licenses properties
|
||||||
|
const licenses = Object.fromEntries((await graphql(queries.licenses())).licenses.map(license => [license.key, license]))
|
||||||
|
for (const license of Object.values(licenses))
|
||||||
|
[...license.limitations, ...license.conditions, ...license.permissions].flat().map(({key, label}) => text[key] = label)
|
||||||
|
colors(licenses)
|
||||||
|
|
||||||
|
//Check if licensed exists
|
||||||
|
if (await imports.which("licensed")) {
|
||||||
|
//Setup for licensed
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > licenses > searching dependencies licenses using licensed`)
|
||||||
|
const path = imports.paths.join(imports.os.tmpdir(), `${repository.databaseId}`)
|
||||||
|
//Create temporary directory
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > licenses > creating temp dir ${path}`)
|
||||||
|
await imports.fs.rmdir(path, {recursive:true})
|
||||||
|
await imports.fs.mkdir(path, {recursive:true})
|
||||||
|
//Clone repository
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > licenses > cloning temp git repository ${repository.url} to ${path}`)
|
||||||
|
const git = imports.git(path)
|
||||||
|
await git.clone(repository.url, path)
|
||||||
|
//Run setup
|
||||||
|
if (setup) {
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > licenses > running setup [${setup}]`)
|
||||||
|
await imports.run(setup, {cwd:path}, {prefixed:false})
|
||||||
|
}
|
||||||
|
//Create configuration file if needed
|
||||||
|
if (!(await imports.fs.stat(imports.paths.join(path, ".licensed.yml")).then(() => 1).catch(() => 0))) {
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > licenses > building .licensed.yml configuration file`)
|
||||||
|
await imports.fs.writeFile(imports.paths.join(path, ".licensed.yml"), [
|
||||||
|
"cache_path: .licensed",
|
||||||
|
].join("\n"))
|
||||||
|
}
|
||||||
|
else
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > licenses > a .licensed.yml configuration file already exists`)
|
||||||
|
//Spawn licensed process
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > licenses > running licensed`)
|
||||||
|
JSON.parse(await imports.run("licensed list --format=json --licenses", {cwd:path})).apps
|
||||||
|
.map(({sources}) => sources?.flatMap(source => source.dependencies.map(({dependency, license}) => {
|
||||||
|
used[license] = (used[license] ?? 0) + 1
|
||||||
|
result.dependencies.push(dependency)
|
||||||
|
result.known += (license in licenses)
|
||||||
|
result.unknown += !(license in licenses)
|
||||||
|
})))
|
||||||
|
//Cleaning
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > licensed > cleaning temp dir ${path}`)
|
||||||
|
await imports.fs.rmdir(path, {recursive:true})
|
||||||
|
}
|
||||||
|
else
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > licenses > licensed not available`)
|
||||||
|
|
||||||
|
//List licenses properties
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > licenses > compute licenses properties`)
|
||||||
|
const base = {permissions:new Set(), limitations:new Set(), conditions:new Set()}
|
||||||
|
const combined = {permissions:new Set(), limitations:new Set(), conditions:new Set()}
|
||||||
|
const detected = Object.entries(used).map(([key, _value]) => ({key}))
|
||||||
|
for (const properties of Object.keys(base)) {
|
||||||
|
//Base license
|
||||||
|
if (repository.licenseInfo)
|
||||||
|
licenses[repository.licenseInfo.key]?.[properties]?.map(({key}) => base[properties].add(key))
|
||||||
|
//Combined licenses
|
||||||
|
for (const {key} of detected)
|
||||||
|
licenses[key]?.[properties]?.map(({key}) => combined[properties].add(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
//Merge limitations and conditions
|
||||||
|
for (const properties of ["limitations", "conditions"])
|
||||||
|
result[properties] = [[...base[properties]].map(key => ({key, text:text[key], inherited:false})), [...combined[properties]].filter(key => !base[properties].has(key)).map(key => ({key, text:text[key], inherited:true}))].flat()
|
||||||
|
//Remove base permissions conflicting with inherited limitations
|
||||||
|
result.permissions = [...base.permissions].filter(key => !combined.limitations.has(key)).map(key => ({key, text:text[key]}))
|
||||||
|
|
||||||
|
//Count used licenses
|
||||||
|
console.debug(`metrics/compute/${login}/plugins > licenses > computing ratio`)
|
||||||
|
const total = Object.values(used).reduce((a, b) => a + b, 0)
|
||||||
|
//Format used licenses and compute positions
|
||||||
|
const list = Object.entries(used).map(([key, count]) => ({name:licenses[key]?.spdxId ?? `${key.charAt(0).toLocaleUpperCase()}${key.substring(1)}`, key, count, value:count/total, x:0, color:licenses[key]?.color ?? "#6e7681", order:licenses[key]?.order ?? -1})).sort((a, b) => a.order === b.order ? b.count - a.count : b.order - a.order)
|
||||||
|
for (let i = 0; i < list.length; i++)
|
||||||
|
list[i].x = (list[i-1]?.x ?? 0) + (list[i-1]?.value ?? 0)
|
||||||
|
//Save ratios
|
||||||
|
result.list = list
|
||||||
|
|
||||||
|
//Results
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
//Handle errors
|
||||||
|
catch (error) {
|
||||||
|
throw {error:{message:"An error occured", instance:error}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**Licenses colorizer (based on categorie) */
|
||||||
|
function colors(licenses) {
|
||||||
|
for (const [license, value] of Object.entries(licenses)) {
|
||||||
|
const [permissions, conditions] = [value.permissions, value.conditions].map(properties => properties.map(({key}) => key))
|
||||||
|
switch (true) {
|
||||||
|
//Other licenses
|
||||||
|
case (license === "other"):{
|
||||||
|
value.color = "#8b949e"
|
||||||
|
value.order = 0
|
||||||
|
break
|
||||||
|
}
|
||||||
|
//Strongly protective licenses and network protective
|
||||||
|
case ((conditions.includes("disclose-source"))&&(conditions.includes("same-license"))&&(conditions.includes("network-use-disclose"))):{
|
||||||
|
value.color = "#388bfd"
|
||||||
|
value.order = 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
//Strongly protective licenses
|
||||||
|
case ((conditions.includes("disclose-source"))&&(conditions.includes("same-license"))):{
|
||||||
|
value.color = "#79c0ff"
|
||||||
|
value.order = 2
|
||||||
|
break
|
||||||
|
}
|
||||||
|
//Weakly protective licenses
|
||||||
|
case ((conditions.includes("disclose-source"))&&(conditions.includes("same-license--library"))):{
|
||||||
|
value.color = "#7ee787"
|
||||||
|
value.order = 3
|
||||||
|
break
|
||||||
|
}
|
||||||
|
//Permissive license
|
||||||
|
case ((permissions.includes("private-use"))&&(permissions.includes("commercial-use"))&&(permissions.includes("modifications"))&&(permissions.includes("distribution"))):{
|
||||||
|
value.color = "#56d364"
|
||||||
|
value.order = 4
|
||||||
|
break
|
||||||
|
}
|
||||||
|
//Unknown
|
||||||
|
default:{
|
||||||
|
value.color = "#6e7681"
|
||||||
|
value.order = -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
source/plugins/licenses/metadata.yml
Normal file
32
source/plugins/licenses/metadata.yml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: "📜 Licenses"
|
||||||
|
cost: N/A
|
||||||
|
supports:
|
||||||
|
- repository
|
||||||
|
inputs:
|
||||||
|
|
||||||
|
# Enable or disable plugin
|
||||||
|
plugin_licenses:
|
||||||
|
description: Display licenses informations
|
||||||
|
type: boolean
|
||||||
|
default: no
|
||||||
|
|
||||||
|
# Command to use to setup target repository
|
||||||
|
# It is required to install all dependencies that will be analyzed with github/licensed
|
||||||
|
plugin_licenses_setup:
|
||||||
|
description: Command to setup target repository
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
|
example: npm ci
|
||||||
|
|
||||||
|
# Display used licenses from both repository license and dependencies licenses ratio
|
||||||
|
plugin_licenses_ratio:
|
||||||
|
description: Display used licenses ratio
|
||||||
|
type: boolean
|
||||||
|
default: no
|
||||||
|
|
||||||
|
# Display permissions, limitations and conditions from both repository license and dependencies licenses
|
||||||
|
# Note that this is NOT legal advice, use at your own risk
|
||||||
|
plugin_licenses_legal:
|
||||||
|
description: Display legal informations about used licenses
|
||||||
|
type: boolean
|
||||||
|
default: yes
|
||||||
20
source/plugins/licenses/queries/licenses.graphql
Normal file
20
source/plugins/licenses/queries/licenses.graphql
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
query LicensesDefault {
|
||||||
|
licenses {
|
||||||
|
spdxId
|
||||||
|
name
|
||||||
|
nickname
|
||||||
|
key
|
||||||
|
limitations {
|
||||||
|
key
|
||||||
|
label
|
||||||
|
}
|
||||||
|
conditions {
|
||||||
|
key
|
||||||
|
label
|
||||||
|
}
|
||||||
|
permissions {
|
||||||
|
key
|
||||||
|
label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
source/plugins/licenses/queries/repository.graphql
Normal file
14
source/plugins/licenses/queries/repository.graphql
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
query LicensesRepository {
|
||||||
|
$account(login: "$owner") {
|
||||||
|
repository(name: "$name") {
|
||||||
|
licenseInfo {
|
||||||
|
spdxId
|
||||||
|
name
|
||||||
|
nickname
|
||||||
|
key
|
||||||
|
}
|
||||||
|
url
|
||||||
|
databaseId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
source/plugins/licenses/tests.yml
Normal file
13
source/plugins/licenses/tests.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
- name: Licenses plugin (complete)
|
||||||
|
uses: lowlighter/metrics@latest
|
||||||
|
with:
|
||||||
|
token: MOCKED_TOKEN
|
||||||
|
template: repository
|
||||||
|
query: '{"repo":"metrics"}'
|
||||||
|
plugin_licenses: yes
|
||||||
|
plugin_licenses_setup: npm ci
|
||||||
|
plugin_licenses_ratio: yes
|
||||||
|
plugin_licenses_legal: yes
|
||||||
|
timeout: 1200000
|
||||||
|
modes:
|
||||||
|
- action
|
||||||
@@ -635,6 +635,57 @@
|
|||||||
border-radius: 7px;
|
border-radius: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Licenses */
|
||||||
|
.licenses {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.licenses .column {
|
||||||
|
align-items: flex-start;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666666;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.licenses-details {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
.field.license.details {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.field.license.details small {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
color: #666666;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.licenses .column:nth-child(1) {
|
||||||
|
margin-left: 13px;
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
.licenses .column:nth-child(2) {
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
.licenses .column:nth-child(3) {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
.licenses .column svg {
|
||||||
|
height: 12px;
|
||||||
|
width: 12px;
|
||||||
|
}
|
||||||
|
.licenses .column .title {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-left: 15px;
|
||||||
|
}
|
||||||
|
.licenses .column .permission svg {
|
||||||
|
fill: #56d364;
|
||||||
|
}
|
||||||
|
.licenses .column .limitation svg {
|
||||||
|
fill: #f85149;
|
||||||
|
}
|
||||||
|
.licenses .column .condition svg {
|
||||||
|
fill: #58a6ff;
|
||||||
|
}
|
||||||
|
|
||||||
/* Fade animation */
|
/* Fade animation */
|
||||||
.af {
|
.af {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|||||||
@@ -6,5 +6,6 @@
|
|||||||
"pagespeed",
|
"pagespeed",
|
||||||
"stargazers",
|
"stargazers",
|
||||||
"people",
|
"people",
|
||||||
"activity"
|
"activity",
|
||||||
|
"licenses"
|
||||||
]
|
]
|
||||||
120
source/templates/repository/partials/licenses.ejs
Normal file
120
source/templates/repository/partials/licenses.ejs
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
<% if (plugins.licenses) { %>
|
||||||
|
<section>
|
||||||
|
<h2 class="field">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8.75.75a.75.75 0 00-1.5 0V2h-.984c-.305 0-.604.08-.869.23l-1.288.737A.25.25 0 013.984 3H1.75a.75.75 0 000 1.5h.428L.066 9.192a.75.75 0 00.154.838l.53-.53-.53.53v.001l.002.002.002.002.006.006.016.015.045.04a3.514 3.514 0 00.686.45A4.492 4.492 0 003 11c.88 0 1.556-.22 2.023-.454a3.515 3.515 0 00.686-.45l.045-.04.016-.015.006-.006.002-.002.001-.002L5.25 9.5l.53.53a.75.75 0 00.154-.838L3.822 4.5h.162c.305 0 .604-.08.869-.23l1.289-.737a.25.25 0 01.124-.033h.984V13h-2.5a.75.75 0 000 1.5h6.5a.75.75 0 000-1.5h-2.5V3.5h.984a.25.25 0 01.124.033l1.29.736c.264.152.563.231.868.231h.162l-2.112 4.692a.75.75 0 00.154.838l.53-.53-.53.53v.001l.002.002.002.002.006.006.016.015.045.04a3.517 3.517 0 00.686.45A4.492 4.492 0 0013 11c.88 0 1.556-.22 2.023-.454a3.512 3.512 0 00.686-.45l.045-.04.01-.01.006-.005.006-.006.002-.002.001-.002-.529-.531.53.53a.75.75 0 00.154-.838L13.823 4.5h.427a.75.75 0 000-1.5h-2.234a.25.25 0 01-.124-.033l-1.29-.736A1.75 1.75 0 009.735 2H8.75V.75zM1.695 9.227c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L3 6.327l-1.305 2.9zm10 0c.285.135.718.273 1.305.273s1.02-.138 1.305-.273L13 6.327l-1.305 2.9z"></path></svg>
|
||||||
|
Licenses
|
||||||
|
</h2>
|
||||||
|
<% if (plugins.licenses.error) { %>
|
||||||
|
<section>
|
||||||
|
<div class="field error">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M2.343 13.657A8 8 0 1113.657 2.343 8 8 0 012.343 13.657zM6.03 4.97a.75.75 0 00-1.06 1.06L6.94 8 4.97 9.97a.75.75 0 101.06 1.06L8 9.06l1.97 1.97a.75.75 0 101.06-1.06L9.06 8l1.97-1.97a.75.75 0 10-1.06-1.06L8 6.94 6.03 4.97z"></path></svg>
|
||||||
|
<%= plugins.licenses.error.message %>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<% } else { %>
|
||||||
|
<div class="row">
|
||||||
|
<section>
|
||||||
|
<div class="field">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path d="M2.75 1.5a.25.25 0 00-.25.25v11.5c0 .138.112.25.25.25h3.5a.75.75 0 010 1.5h-3.5A1.75 1.75 0 011 13.25V1.75C1 .784 1.784 0 2.75 0h8a1.75 1.75 0 011.508.862.75.75 0 11-1.289.768.25.25 0 00-.219-.13h-8z"></path><path fill-rule="evenodd" d="M8 7a4 4 0 116.49 3.13l.995 4.973a.75.75 0 01-.991.852l-2.409-.876a.25.25 0 00-.17 0l-2.409.876a.75.75 0 01-.991-.852l.994-4.973A3.993 3.993 0 018 7zm4-2.5a2.5 2.5 0 100 5 2.5 2.5 0 000-5zm0 6.5a4 4 0 001.104-.154l.649 3.243-1.155-.42c-.386-.14-.81-.14-1.196 0l-1.155.42.649-3.243A4 4 0 0012 11z"></path></svg>
|
||||||
|
<%= plugins.licenses.default?.spdxId ?? "No license provided" %>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M6.122.392a1.75 1.75 0 011.756 0l5.25 3.045c.54.313.872.89.872 1.514V7.25a.75.75 0 01-1.5 0V5.677L7.75 8.432v6.384a1 1 0 01-1.502.865L.872 12.563A1.75 1.75 0 010 11.049V4.951c0-.624.332-1.2.872-1.514L6.122.392zM7.125 1.69l4.63 2.685L7 7.133 2.245 4.375l4.63-2.685a.25.25 0 01.25 0zM1.5 11.049V5.677l4.75 2.755v5.516l-4.625-2.683a.25.25 0 01-.125-.216zm10.828 3.684a.75.75 0 101.087 1.034l2.378-2.5a.75.75 0 000-1.034l-2.378-2.5a.75.75 0 00-1.087 1.034L13.501 12H10.25a.75.75 0 000 1.5h3.251l-1.173 1.233z"></path></svg>
|
||||||
|
<%= plugins.licenses.dependencies.length %> dependenc<%= s(plugins.licenses.dependencies.length, "y") %>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<div class="field">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M9.585.52a2.678 2.678 0 00-3.17 0l-.928.68a1.178 1.178 0 01-.518.215L3.83 1.59a2.678 2.678 0 00-2.24 2.24l-.175 1.14a1.178 1.178 0 01-.215.518l-.68.928a2.678 2.678 0 000 3.17l.68.928c.113.153.186.33.215.518l.175 1.138a2.678 2.678 0 002.24 2.24l1.138.175c.187.029.365.102.518.215l.928.68a2.678 2.678 0 003.17 0l.928-.68a1.17 1.17 0 01.518-.215l1.138-.175a2.678 2.678 0 002.241-2.241l.175-1.138c.029-.187.102-.365.215-.518l.68-.928a2.678 2.678 0 000-3.17l-.68-.928a1.179 1.179 0 01-.215-.518L14.41 3.83a2.678 2.678 0 00-2.24-2.24l-1.138-.175a1.179 1.179 0 01-.518-.215L9.585.52zM7.303 1.728c.415-.305.98-.305 1.394 0l.928.68c.348.256.752.423 1.18.489l1.136.174c.51.078.909.478.987.987l.174 1.137c.066.427.233.831.489 1.18l.68.927c.305.415.305.98 0 1.394l-.68.928a2.678 2.678 0 00-.489 1.18l-.174 1.136a1.178 1.178 0 01-.987.987l-1.137.174a2.678 2.678 0 00-1.18.489l-.927.68c-.415.305-.98.305-1.394 0l-.928-.68a2.678 2.678 0 00-1.18-.489l-1.136-.174a1.178 1.178 0 01-.987-.987l-.174-1.137a2.678 2.678 0 00-.489-1.18l-.68-.927a1.178 1.178 0 010-1.394l.68-.928c.256-.348.423-.752.489-1.18l.174-1.136c.078-.51.478-.909.987-.987l1.137-.174a2.678 2.678 0 001.18-.489l.927-.68zM11.28 6.78a.75.75 0 00-1.06-1.06L7 8.94 5.78 7.72a.75.75 0 00-1.06 1.06l1.75 1.75a.75.75 0 001.06 0l3.75-3.75z"></path></svg>
|
||||||
|
<%= plugins.licenses.known %> known license<%= s(plugins.licenses.known) %> used
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M6.415.52a2.678 2.678 0 013.17 0l.928.68c.153.113.33.186.518.215l1.138.175a2.678 2.678 0 012.241 2.24l.175 1.138c.029.187.102.365.215.518l.68.928a2.678 2.678 0 010 3.17l-.68.928a1.179 1.179 0 00-.215.518l-.175 1.138a2.678 2.678 0 01-2.241 2.241l-1.138.175a1.179 1.179 0 00-.518.215l-.928.68a2.678 2.678 0 01-3.17 0l-.928-.68a1.179 1.179 0 00-.518-.215L3.83 14.41a2.678 2.678 0 01-2.24-2.24l-.175-1.138a1.179 1.179 0 00-.215-.518l-.68-.928a2.678 2.678 0 010-3.17l.68-.928a1.17 1.17 0 00.215-.518l.175-1.14a2.678 2.678 0 012.24-2.24l1.138-.175c.187-.029.365-.102.518-.215l.928-.68zm2.282 1.209a1.178 1.178 0 00-1.394 0l-.928.68a2.678 2.678 0 01-1.18.489l-1.136.174a1.178 1.178 0 00-.987.987l-.174 1.137a2.678 2.678 0 01-.489 1.18l-.68.927c-.305.415-.305.98 0 1.394l.68.928c.256.348.423.752.489 1.18l.174 1.136c.078.51.478.909.987.987l1.137.174c.427.066.831.233 1.18.489l.927.68c.415.305.98.305 1.394 0l.928-.68a2.678 2.678 0 011.18-.489l1.136-.174c.51-.078.909-.478.987-.987l.174-1.137c.066-.427.233-.831.489-1.18l.68-.927c.305-.415.305-.98 0-1.394l-.68-.928a2.678 2.678 0 01-.489-1.18l-.174-1.136a1.178 1.178 0 00-.987-.987l-1.137-.174a2.678 2.678 0 01-1.18-.489l-.927-.68zM9 11a1 1 0 11-2 0 1 1 0 012 0zM6.92 6.085c.081-.16.19-.299.34-.398.145-.097.371-.187.74-.187.28 0 .553.087.738.225A.613.613 0 019 6.25c0 .177-.04.264-.077.318a.956.956 0 01-.277.245c-.076.051-.158.1-.258.161l-.007.004c-.093.056-.204.122-.313.195a2.416 2.416 0 00-.692.661.75.75 0 001.248.832.956.956 0 01.276-.245 6.3 6.3 0 01.26-.16l.006-.004c.093-.057.204-.123.313-.195.222-.149.487-.355.692-.662.214-.32.329-.702.329-1.15 0-.76-.36-1.348-.862-1.725A2.76 2.76 0 008 4c-.631 0-1.154.16-1.572.438-.413.276-.68.638-.849.977a.75.75 0 001.342.67z"></path></svg>
|
||||||
|
<%= plugins.licenses.unknown %> unknown license<%= s(plugins.licenses.unknown) %> used
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<% if (plugins.licenses.ratio) { %>
|
||||||
|
<div class="licenses-details">
|
||||||
|
<section class="column">
|
||||||
|
<svg class="bar" xmlns="http://www.w3.org/2000/svg" width="460" height="8">
|
||||||
|
<mask id="licenses-bar">
|
||||||
|
<rect x="0" y="0" width="460" height="8" fill="white" rx="5"/>
|
||||||
|
</mask>
|
||||||
|
<rect mask="url(#licenses-bar)" x="0" y="0" width="<%= plugins.licenses.list.length ? 0 : 460 %>" height="8" fill="#d1d5da"/>
|
||||||
|
<% for (const {name, value, color, x} of plugins.licenses.list) { %>
|
||||||
|
<rect mask="url(#licenses-bar)" x="<%= x*460 %>" y="0" width="<%= value*460 %>" height="8" fill="<%= color %>"/>
|
||||||
|
<% } %>
|
||||||
|
</svg>
|
||||||
|
</section>
|
||||||
|
<div class="row fill-width">
|
||||||
|
<% for (const row of [0, 1]) { %>
|
||||||
|
<section>
|
||||||
|
<% for (const {name, value, color, count} of plugins.licenses.list.filter((_, i) => i%2 === row)) { %>
|
||||||
|
<div class="field license details">
|
||||||
|
<div class="field">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill="<%= color %>" fill-rule="evenodd" d="M8 4a4 4 0 100 8 4 4 0 000-8z"></path></svg>
|
||||||
|
<%= f.ellipsis(name) %>
|
||||||
|
</div>
|
||||||
|
<small><div><%= count %></div></small>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</section>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
<% if (plugins.licenses.legal) { %>
|
||||||
|
<div class="row licenses-details">
|
||||||
|
<section class="licenses">
|
||||||
|
<% if (plugins.licenses.permissions?.length) { %>
|
||||||
|
<div class="column">
|
||||||
|
<div class="title">Permissions</div>
|
||||||
|
<% for (const {text, disabled} of plugins.licenses.permissions) { %>
|
||||||
|
<div class="permission <%= disabled ? "disabled" : "" %>">
|
||||||
|
<% if (disabled) { %>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M6.122.392a1.75 1.75 0 011.756 0l5.25 3.045c.54.313.872.89.872 1.514V7.25a.75.75 0 01-1.5 0V5.677L7.75 8.432v6.384a1 1 0 01-1.502.865L.872 12.563A1.75 1.75 0 010 11.049V4.951c0-.624.332-1.2.872-1.514L6.122.392zM7.125 1.69l4.63 2.685L7 7.133 2.245 4.375l4.63-2.685a.25.25 0 01.25 0zM1.5 11.049V5.677l4.75 2.755v5.516l-4.625-2.683a.25.25 0 01-.125-.216zm10.828 3.684a.75.75 0 101.087 1.034l2.378-2.5a.75.75 0 000-1.034l-2.378-2.5a.75.75 0 00-1.087 1.034L13.501 12H10.25a.75.75 0 000 1.5h3.251l-1.173 1.233z"></path></svg>
|
||||||
|
<% } else { %>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z"></path></svg>
|
||||||
|
<% } %>
|
||||||
|
<%= text %>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
<% if (plugins.licenses.limitations?.length) { %>
|
||||||
|
<div class="column">
|
||||||
|
<div class="title">Limitations</div>
|
||||||
|
<% for (const {text, inherited} of plugins.licenses.limitations) { %>
|
||||||
|
<div class="limitation">
|
||||||
|
<% if (inherited) { %>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M6.122.392a1.75 1.75 0 011.756 0l5.25 3.045c.54.313.872.89.872 1.514V7.25a.75.75 0 01-1.5 0V5.677L7.75 8.432v6.384a1 1 0 01-1.502.865L.872 12.563A1.75 1.75 0 010 11.049V4.951c0-.624.332-1.2.872-1.514L6.122.392zM7.125 1.69l4.63 2.685L7 7.133 2.245 4.375l4.63-2.685a.25.25 0 01.25 0zM1.5 11.049V5.677l4.75 2.755v5.516l-4.625-2.683a.25.25 0 01-.125-.216zm10.828 3.684a.75.75 0 101.087 1.034l2.378-2.5a.75.75 0 000-1.034l-2.378-2.5a.75.75 0 00-1.087 1.034L13.501 12H10.25a.75.75 0 000 1.5h3.251l-1.173 1.233z"></path></svg>
|
||||||
|
<% } else { %>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z"></path></svg>
|
||||||
|
<% } %>
|
||||||
|
<%= text %>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
<% if (plugins.licenses.conditions?.length) { %>
|
||||||
|
<div class="column">
|
||||||
|
<div class="title">Conditions</div>
|
||||||
|
<% for (const {text, inherited} of plugins.licenses.conditions) { %>
|
||||||
|
<div class="condition">
|
||||||
|
<% if (inherited) { %>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M6.122.392a1.75 1.75 0 011.756 0l5.25 3.045c.54.313.872.89.872 1.514V7.25a.75.75 0 01-1.5 0V5.677L7.75 8.432v6.384a1 1 0 01-1.502.865L.872 12.563A1.75 1.75 0 010 11.049V4.951c0-.624.332-1.2.872-1.514L6.122.392zM7.125 1.69l4.63 2.685L7 7.133 2.245 4.375l4.63-2.685a.25.25 0 01.25 0zM1.5 11.049V5.677l4.75 2.755v5.516l-4.625-2.683a.25.25 0 01-.125-.216zm10.828 3.684a.75.75 0 101.087 1.034l2.378-2.5a.75.75 0 000-1.034l-2.378-2.5a.75.75 0 00-1.087 1.034L13.501 12H10.25a.75.75 0 000 1.5h3.251l-1.173 1.233z"></path></svg>
|
||||||
|
<% } else { %>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM0 8a8 8 0 1116 0A8 8 0 010 8zm6.5-.25A.75.75 0 017.25 7h1a.75.75 0 01.75.75v2.75h.25a.75.75 0 010 1.5h-2a.75.75 0 010-1.5h.25v-2h-.25a.75.75 0 01-.75-.75zM8 6a1 1 0 100-2 1 1 0 000 2z"></path></svg>
|
||||||
|
<% } %>
|
||||||
|
<%= text %>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
<% } %>
|
||||||
|
</section>
|
||||||
|
<% } %>
|
||||||
Reference in New Issue
Block a user