[PUI] Add licenses texts to PUI (#6855)

* compile a license texts bundle

* add backend license extraction on install

* change path for licenses

* add to gitignore

* Add api to expose license paths

* add texts

* add frontend rendering of licensing files

* Handle errors when fetching license information

* Format backend packages.txt in json

* Improved API rendering:

- Handle file errors
- Render as JSON object

* Improve frontend modal rendering

- Separate frontend / backend into tabs
- Split packages into accordion

* Generate JSON file for fronten deps

* Fix rendering for frontend deps

* Update src/frontend/src/components/modals/LicenseModal.tsx

Co-authored-by: Lukas <76838159+wolflu05@users.noreply.github.com>

* Update src/frontend/src/components/modals/LicenseModal.tsx

Co-authored-by: Lukas <76838159+wolflu05@users.noreply.github.com>

* make reading of licenses objects dynamic

* remove unsued import

* style fixes

* style fixes

* default to first value

* use new syntax to call docker compose

* merge fix

* fix path

* Roll back #6942

* Update qc_checks.yaml

Run migration checks when requirements file changes

---------

Co-authored-by: Oliver Walters <oliver.henry.walters@gmail.com>
Co-authored-by: Lukas <76838159+wolflu05@users.noreply.github.com>
This commit is contained in:
Matthias Mair 2024-04-04 00:31:20 +01:00 committed by GitHub
parent 7cbf99bea7
commit fddcb629b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 308 additions and 13 deletions

View File

@ -48,8 +48,9 @@ jobs:
migrations: migrations:
- '**/migrations/**' - '**/migrations/**'
- '.github/workflows**' - '.github/workflows**'
- 'src/backend/requirements.txt'
api: api:
- 'InvenTree/InvenTree/api_version.py' - 'src/backend/InvenTree/InvenTree/api_version.py'
frontend: frontend:
- 'src/frontend/**' - 'src/frontend/**'

1
.gitignore vendored
View File

@ -85,6 +85,7 @@ env/
# Locale stats file # Locale stats file
src/backend/InvenTree/InvenTree/locale_stats.json src/backend/InvenTree/InvenTree/locale_stats.json
src/backend/InvenTree/InvenTree/licenses.txt
# node.js # node.js
node_modules/ node_modules/

View File

@ -1,6 +1,9 @@
"""Main JSON interface views.""" """Main JSON interface views."""
import json
import logging
import sys import sys
from pathlib import Path
from django.conf import settings from django.conf import settings
from django.db import transaction from django.db import transaction
@ -31,6 +34,60 @@ from .status import check_system_health, is_worker_running
from .version import inventreeApiText from .version import inventreeApiText
from .views import AjaxView from .views import AjaxView
logger = logging.getLogger('inventree')
class LicenseViewSerializer(serializers.Serializer):
"""Serializer for license information."""
backend = serializers.CharField(help_text='Backend licenses texts', read_only=True)
frontend = serializers.CharField(
help_text='Frontend licenses texts', read_only=True
)
class LicenseView(APIView):
"""Simple JSON endpoint for InvenTree license information."""
permission_classes = [permissions.IsAuthenticated]
def read_license_file(self, path: Path) -> list:
"""Extract license information from the provided file.
Arguments:
path: Path to the license file
Returns: A list of items containing the license information
"""
# Check if the file exists
if not path.exists():
logger.error("License file not found at '%s'", path)
return []
try:
data = json.loads(path.read_text())
except json.JSONDecodeError as e:
logger.exception("Failed to parse license file '%s': %s", path, e)
return []
except Exception as e:
logger.exception("Exception while reading license file '%s': %s", path, e)
return []
# Ensure consistent string between backend and frontend licenses
return [{key.lower(): value for key, value in entry.items()} for entry in data]
@extend_schema(responses={200: OpenApiResponse(response=LicenseViewSerializer)})
def get(self, request, *args, **kwargs):
"""Return information about the InvenTree server."""
backend = Path(__file__).parent.joinpath('licenses.txt')
frontend = Path(__file__).parent.parent.joinpath(
'web/static/web/.vite/dependencies.json'
)
return JsonResponse({
'backend': self.read_license_file(backend),
'frontend': self.read_license_file(frontend),
})
class VersionViewSerializer(serializers.Serializer): class VersionViewSerializer(serializers.Serializer):
"""Serializer for a single version.""" """Serializer for a single version."""

View File

@ -1,11 +1,14 @@
"""InvenTree API version information.""" """InvenTree API version information."""
# InvenTree API version # InvenTree API version
INVENTREE_API_VERSION = 185 INVENTREE_API_VERSION = 186
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" """Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """ INVENTREE_API_TEXT = """
v186 - 2024-03-26 : https://github.com/inventree/InvenTree/pull/6855
- Adds license information to the API
v185 - 2024-03-24 : https://github.com/inventree/InvenTree/pull/6836 v185 - 2024-03-24 : https://github.com/inventree/InvenTree/pull/6836
- Remove /plugin/activate endpoint - Remove /plugin/activate endpoint
- Update docstrings and typing for various API endpoints (no functional changes) - Update docstrings and typing for various API endpoints (no functional changes)

View File

@ -39,7 +39,14 @@ from stock.urls import stock_urls
from web.urls import api_urls as web_api_urls from web.urls import api_urls as web_api_urls
from web.urls import urlpatterns as platform_urls from web.urls import urlpatterns as platform_urls
from .api import APISearchView, InfoView, NotFoundView, VersionTextView, VersionView from .api import (
APISearchView,
InfoView,
LicenseView,
NotFoundView,
VersionTextView,
VersionView,
)
from .magic_login import GetSimpleLoginView from .magic_login import GetSimpleLoginView
from .social_auth_urls import ( from .social_auth_urls import (
EmailListView, EmailListView,
@ -99,6 +106,7 @@ apipatterns = [
name='schema', name='schema',
), ),
# InvenTree information endpoints # InvenTree information endpoints
path('license/', LicenseView.as_view(), name='api-license'), # license info
path( path(
'version-text', VersionTextView.as_view(), name='api-version-text' 'version-text', VersionTextView.as_view(), name='api-version-text'
), # version text ), # version text

View File

@ -18,7 +18,7 @@ django-maintenance-mode # Shut down application while reloading
django-markdownify # Markdown rendering django-markdownify # Markdown rendering
django-mptt # Modified Preorder Tree Traversal django-mptt # Modified Preorder Tree Traversal
django-markdownify # Markdown rendering django-markdownify # Markdown rendering
django-money>=3.0.0,<3.5.0 # Django app for currency management # FIXED 2023-10-31 3.3.0 breaks due to https://github.com/django-money/django-money/issues/731 django-money>=3.0.0,<3.3.0 # Django app for currency management # FIXED 2023-10-31 3.3.0 breaks due to https://github.com/django-money/django-money/issues/731
django-mptt # Modified Preorder Tree Traversal django-mptt # Modified Preorder Tree Traversal
django-redis>=5.0.0 # Redis integration django-redis>=5.0.0 # Redis integration
django-q2 # Background task scheduling django-q2 # Background task scheduling
@ -41,6 +41,7 @@ gunicorn # Gunicorn web server
pdf2image # PDF to image conversion pdf2image # PDF to image conversion
pillow # Image manipulation pillow # Image manipulation
pint==0.21 # Unit conversion # FIXED 2023-05-30 breaks tests https://github.com/matmair/InvenTree/actions/runs/5095665936/jobs/9160852560 pint==0.21 # Unit conversion # FIXED 2023-05-30 breaks tests https://github.com/matmair/InvenTree/actions/runs/5095665936/jobs/9160852560
pip-licenses # License information for installed packages
python-barcode[images] # Barcode generator python-barcode[images] # Barcode generator
python-dotenv # Environment variable management python-dotenv # Environment variable management
pyyaml>=6.0.1 # YAML parsing pyyaml>=6.0.1 # YAML parsing

View File

@ -96,7 +96,7 @@ django-js-asset==2.2.0
# via django-mptt # via django-mptt
django-maintenance-mode==0.21.1 django-maintenance-mode==0.21.1
django-markdownify==0.9.3 django-markdownify==0.9.3
django-money==3.4.1 django-money==3.2.0
django-mptt==0.16.0 django-mptt==0.16.0
django-otp==1.3.0 django-otp==1.3.0
# via django-allauth-2fa # via django-allauth-2fa
@ -230,6 +230,9 @@ pillow==10.2.0
# qrcode # qrcode
# weasyprint # weasyprint
pint==0.21 pint==0.21
pip-licenses==4.3.4
prettytable==3.10.0
# via pip-licenses
protobuf==4.25.3 protobuf==4.25.3
# via # via
# googleapis-common-protos # googleapis-common-protos
@ -329,6 +332,8 @@ urllib3==2.2.1
# dulwich # dulwich
# requests # requests
# sentry-sdk # sentry-sdk
wcwidth==0.2.13
# via prettytable
weasyprint==61.2 weasyprint==61.2
# via django-weasyprint # via django-weasyprint
webencodings==0.5.1 webencodings==0.5.1

View File

@ -65,6 +65,7 @@
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
"@vitejs/plugin-react": "^4.2.1", "@vitejs/plugin-react": "^4.2.1",
"babel-plugin-macros": "^3.1.0", "babel-plugin-macros": "^3.1.0",
"rollup-plugin-license": "^3.3.1",
"nyc": "^15.1.0", "nyc": "^15.1.0",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "^5.2.7", "vite": "^5.2.7",

View File

@ -0,0 +1,90 @@
import { Trans, t } from '@lingui/macro';
import {
Accordion,
Alert,
Divider,
Group,
LoadingOverlay,
Space,
Stack,
Tabs,
Text
} from '@mantine/core';
import { useQuery } from '@tanstack/react-query';
import { api } from '../../App';
import { ApiEndpoints } from '../../enums/ApiEndpoints';
import { apiUrl } from '../../states/ApiState';
export function LicenceView(entries: Readonly<any[]>) {
return (
<Stack spacing="xs">
<Divider />
{entries?.length > 0 && (
<Accordion variant="contained" defaultValue="-">
{entries?.map((entry: any, index: number) => (
<Accordion.Item key={entry.name} value={`entry-${index}`}>
<Accordion.Control>
<Group position="apart" grow>
<Text>{entry.name}</Text>
<Text>{entry.license}</Text>
<Space />
<Text>{entry.version}</Text>
</Group>
</Accordion.Control>
<Accordion.Panel style={{ whiteSpace: 'pre-line' }}>
{entry.licensetext || t`No license text available`}
</Accordion.Panel>
</Accordion.Item>
))}
</Accordion>
)}
</Stack>
);
}
export function LicenseModal() {
const { data, isFetching, isError } = useQuery({
queryKey: ['license'],
queryFn: () =>
api
.get(apiUrl(ApiEndpoints.license))
.then((res) => res.data ?? {})
.catch(() => {})
});
return (
<Stack spacing="xs">
<Divider />
<LoadingOverlay visible={isFetching} />
{isFetching && (
<Text>
<Trans>Loading license information</Trans>
</Text>
)}
{isError ? (
<Alert color="red" title={t`Error`}>
<Text>
<Trans>Failed to fetch license information</Trans>
</Text>
</Alert>
) : (
<Tabs defaultValue={Object.keys(data)[0] ?? ''}>
<Tabs.List>
{Object.keys(data ?? {}).map((key) => (
<Tabs.Tab key={key} value={key}>
<Trans>{key} Packages</Trans>
</Tabs.Tab>
))}
</Tabs.List>
{Object.keys(data ?? {}).map((key) => (
<Tabs.Panel key={key} value={key}>
{LicenceView(data[key] ?? [])}
</Tabs.Panel>
))}
</Tabs>
)}
</Stack>
);
}

View File

@ -10,6 +10,7 @@ import { ModalsProvider } from '@mantine/modals';
import { Notifications } from '@mantine/notifications'; import { Notifications } from '@mantine/notifications';
import { AboutInvenTreeModal } from '../components/modals/AboutInvenTreeModal'; import { AboutInvenTreeModal } from '../components/modals/AboutInvenTreeModal';
import { LicenseModal } from '../components/modals/LicenseModal';
import { QrCodeModal } from '../components/modals/QrCodeModal'; import { QrCodeModal } from '../components/modals/QrCodeModal';
import { ServerInfoModal } from '../components/modals/ServerInfoModal'; import { ServerInfoModal } from '../components/modals/ServerInfoModal';
import { useLocalState } from '../states/LocalState'; import { useLocalState } from '../states/LocalState';
@ -65,7 +66,8 @@ export function ThemeContext({ children }: { children: JSX.Element }) {
modals={{ modals={{
qr: QrCodeModal, qr: QrCodeModal,
info: ServerInfoModal, info: ServerInfoModal,
about: AboutInvenTreeModal about: AboutInvenTreeModal,
license: LicenseModal
}} }}
> >
{children} {children}

View File

@ -96,8 +96,19 @@ function aboutInvenTree() {
innerProps: {} innerProps: {}
}); });
} }
function licenseInfo() {
return openContextModal({
modal: 'license',
title: (
<StylishText size="xl">
<Trans>License Information</Trans>
</StylishText>
),
size: 'xl',
innerProps: {}
});
}
// TODO @matmair: Add the following pages and adjust the links
export const aboutLinks: DocumentationLinkItem[] = [ export const aboutLinks: DocumentationLinkItem[] = [
{ {
id: 'instance', id: 'instance',
@ -114,8 +125,7 @@ export const aboutLinks: DocumentationLinkItem[] = [
{ {
id: 'licenses', id: 'licenses',
title: <Trans>Licenses</Trans>, title: <Trans>Licenses</Trans>,
description: <Trans>Licenses for packages used by InvenTree</Trans>, description: <Trans>Licenses for dependencies of the service</Trans>,
link: '/licenses', action: licenseInfo
placeholder: true
} }
]; ];

View File

@ -40,6 +40,7 @@ export enum ApiEndpoints {
news = 'news/', news = 'news/',
global_status = 'generic/status/', global_status = 'generic/status/',
version = 'version/', version = 'version/',
license = 'license/',
sso_providers = 'auth/providers/', sso_providers = 'auth/providers/',
group_list = 'user/group/', group_list = 'user/group/',
owner_list = 'user/owner/', owner_list = 'user/owner/',

View File

@ -1,5 +1,6 @@
import react from '@vitejs/plugin-react'; import react from '@vitejs/plugin-react';
import { platform, release } from 'node:os'; import { platform, release } from 'node:os';
import license from 'rollup-plugin-license';
import { defineConfig, splitVendorChunkPlugin } from 'vite'; import { defineConfig, splitVendorChunkPlugin } from 'vite';
import istanbul from 'vite-plugin-istanbul'; import istanbul from 'vite-plugin-istanbul';
@ -19,6 +20,19 @@ export default defineConfig({
} }
}), }),
splitVendorChunkPlugin(), splitVendorChunkPlugin(),
license({
sourcemap: true,
thirdParty: {
includePrivate: true,
multipleVersions: true,
output: {
file: '../../InvenTree/web/static/web/.vite/dependencies.json',
template(dependencies) {
return JSON.stringify(dependencies);
}
}
}
}),
istanbul({ istanbul({
include: 'src/*', include: 'src/*',
exclude: ['node_modules', 'test/'], exclude: ['node_modules', 'test/'],

View File

@ -942,7 +942,7 @@
resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280"
integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==
"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15":
version "1.4.15" version "1.4.15"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
@ -1769,6 +1769,11 @@ aria-hidden@^1.1.3:
dependencies: dependencies:
tslib "^2.0.0" tslib "^2.0.0"
array-find-index@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
integrity sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==
asynckit@^0.4.0: asynckit@^0.4.0:
version "0.4.0" version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@ -2061,6 +2066,11 @@ commander@^10.0.0:
resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06"
integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==
commenting@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/commenting/-/commenting-1.1.0.tgz#fae14345c6437b8554f30bc6aa6c1e1633033590"
integrity sha512-YeNK4tavZwtH7jEgK1ZINXzLKm6DZdEMfsaaieOsCAN0S8vsY7UeuO3Q7d/M018EFgE+IeUAuBOKkFccBZsUZA==
commondir@^1.0.1: commondir@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
@ -2481,7 +2491,7 @@ glob-parent@~5.1.0:
dependencies: dependencies:
is-glob "^4.0.1" is-glob "^4.0.1"
glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.2.0:
version "7.2.3" version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
@ -2863,7 +2873,7 @@ lodash.sortby@^4.7.0:
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==
lodash@^4.17.19, lodash@^4.17.21: lodash@^4.17.19, lodash@^4.17.21, lodash@~4.17.21:
version "4.17.21" version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@ -2897,6 +2907,13 @@ lru-cache@^6.0.0:
dependencies: dependencies:
yallist "^4.0.0" yallist "^4.0.0"
magic-string@~0.30.0:
version "0.30.8"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.8.tgz#14e8624246d2bedba70d5462aa99ac9681844613"
integrity sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==
dependencies:
"@jridgewell/sourcemap-codec" "^1.4.15"
make-dir@^3.0.0, make-dir@^3.0.2: make-dir@^3.0.0, make-dir@^3.0.2:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
@ -2958,6 +2975,16 @@ minimatch@^3.0.4, minimatch@^3.1.1:
dependencies: dependencies:
brace-expansion "^1.1.7" brace-expansion "^1.1.7"
mkdirp@~3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50"
integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==
moment@~2.30.1:
version "2.30.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae"
integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==
moo@^0.5.1: moo@^0.5.1:
version "0.5.2" version "0.5.2"
resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.2.tgz#f9fe82473bc7c184b0d32e2215d3f6e67278733c" resolved "https://registry.yarnpkg.com/moo/-/moo-0.5.2.tgz#f9fe82473bc7c184b0d32e2215d3f6e67278733c"
@ -3115,6 +3142,11 @@ package-hash@^4.0.0:
lodash.flattendeep "^4.4.0" lodash.flattendeep "^4.4.0"
release-zalgo "^1.0.0" release-zalgo "^1.0.0"
package-name-regex@~2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/package-name-regex/-/package-name-regex-2.0.6.tgz#b54bcb04d950e38082b7bb38fa558e01c1679334"
integrity sha512-gFL35q7kbE/zBaPA3UKhp2vSzcPYx2ecbYuwv1ucE9Il6IIgBDweBlH8D68UFGZic2MkllKa2KHCfC1IQBQUYA==
parent-module@^1.0.0: parent-module@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
@ -3514,6 +3546,21 @@ rimraf@^3.0.0:
dependencies: dependencies:
glob "^7.1.3" glob "^7.1.3"
rollup-plugin-license@^3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/rollup-plugin-license/-/rollup-plugin-license-3.3.1.tgz#73b68e33477524198d6f3f9befc905f59bf37c53"
integrity sha512-lwZ/J8QgSnP0unVOH2FQuOBkeiyp0EBvrbYdNU33lOaYD8xP9Zoki+PGoWMD31EUq8Q07GGocSABTYlWMKkwuw==
dependencies:
commenting "~1.1.0"
glob "~7.2.0"
lodash "~4.17.21"
magic-string "~0.30.0"
mkdirp "~3.0.0"
moment "~2.30.1"
package-name-regex "~2.0.6"
spdx-expression-validate "~2.0.0"
spdx-satisfies "~5.0.1"
rollup@^4.13.0: rollup@^4.13.0:
version "4.13.0" version "4.13.0"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.13.0.tgz#dd2ae144b4cdc2ea25420477f68d4937a721237a" resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.13.0.tgz#dd2ae144b4cdc2ea25420477f68d4937a721237a"
@ -3643,6 +3690,54 @@ spawn-wrap@^2.0.0:
signal-exit "^3.0.2" signal-exit "^3.0.2"
which "^2.0.1" which "^2.0.1"
spdx-compare@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/spdx-compare/-/spdx-compare-1.0.0.tgz#2c55f117362078d7409e6d7b08ce70a857cd3ed7"
integrity sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==
dependencies:
array-find-index "^1.0.2"
spdx-expression-parse "^3.0.0"
spdx-ranges "^2.0.0"
spdx-exceptions@^2.1.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66"
integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==
spdx-expression-parse@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679"
integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==
dependencies:
spdx-exceptions "^2.1.0"
spdx-license-ids "^3.0.0"
spdx-expression-validate@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/spdx-expression-validate/-/spdx-expression-validate-2.0.0.tgz#25c9408e1c63fad94fff5517bb7101ffcd23350b"
integrity sha512-b3wydZLM+Tc6CFvaRDBOF9d76oGIHNCLYFeHbftFXUWjnfZWganmDmvtM5sm1cRwJc/VDBMLyGGrsLFd1vOxbg==
dependencies:
spdx-expression-parse "^3.0.0"
spdx-license-ids@^3.0.0:
version "3.0.17"
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz#887da8aa73218e51a1d917502d79863161a93f9c"
integrity sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==
spdx-ranges@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/spdx-ranges/-/spdx-ranges-2.1.1.tgz#87573927ba51e92b3f4550ab60bfc83dd07bac20"
integrity sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==
spdx-satisfies@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/spdx-satisfies/-/spdx-satisfies-5.0.1.tgz#9feeb2524686c08e5f7933c16248d4fdf07ed6a6"
integrity sha512-Nwor6W6gzFp8XX4neaKQ7ChV4wmpSh2sSDemMFSzHxpTw460jxFYeOn+jq4ybnSSw/5sc3pjka9MQPouksQNpw==
dependencies:
spdx-compare "^1.0.0"
spdx-expression-parse "^3.0.0"
spdx-ranges "^2.0.0"
sprintf-js@~1.0.2: sprintf-js@~1.0.2:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"

View File

@ -244,6 +244,12 @@ def install(c, uv=False):
# Run plugins install # Run plugins install
plugins(c, uv=uv) plugins(c, uv=uv)
# Compile license information
lic_path = managePyDir().joinpath('InvenTree', 'licenses.txt')
c.run(
f'pip-licenses --format=json --with-license-file --no-license-path > {lic_path}'
)
@task(help={'tests': 'Set up test dataset at the end'}) @task(help={'tests': 'Set up test dataset at the end'})
def setup_dev(c, tests=False): def setup_dev(c, tests=False):