From fddcb629b665c2d65f82963f5823f10d8640b5bb Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Thu, 4 Apr 2024 00:31:20 +0100 Subject: [PATCH] [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 Co-authored-by: Lukas <76838159+wolflu05@users.noreply.github.com> --- .github/workflows/qc_checks.yaml | 3 +- .gitignore | 1 + src/backend/InvenTree/InvenTree/api.py | 57 ++++++++++ .../InvenTree/InvenTree/api_version.py | 5 +- src/backend/InvenTree/InvenTree/urls.py | 10 +- src/backend/requirements.in | 3 +- src/backend/requirements.txt | 7 +- src/frontend/package.json | 1 + .../src/components/modals/LicenseModal.tsx | 90 ++++++++++++++++ src/frontend/src/contexts/ThemeContext.tsx | 4 +- src/frontend/src/defaults/links.tsx | 18 +++- src/frontend/src/enums/ApiEndpoints.tsx | 1 + src/frontend/vite.config.ts | 14 +++ src/frontend/yarn.lock | 101 +++++++++++++++++- tasks.py | 6 ++ 15 files changed, 308 insertions(+), 13 deletions(-) create mode 100644 src/frontend/src/components/modals/LicenseModal.tsx diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 1deaee69d6..2eb77438e7 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -48,8 +48,9 @@ jobs: migrations: - '**/migrations/**' - '.github/workflows**' + - 'src/backend/requirements.txt' api: - - 'InvenTree/InvenTree/api_version.py' + - 'src/backend/InvenTree/InvenTree/api_version.py' frontend: - 'src/frontend/**' diff --git a/.gitignore b/.gitignore index 04cff27c12..8c119f2ab2 100644 --- a/.gitignore +++ b/.gitignore @@ -85,6 +85,7 @@ env/ # Locale stats file src/backend/InvenTree/InvenTree/locale_stats.json +src/backend/InvenTree/InvenTree/licenses.txt # node.js node_modules/ diff --git a/src/backend/InvenTree/InvenTree/api.py b/src/backend/InvenTree/InvenTree/api.py index c5f6c110ae..58aadfb81c 100644 --- a/src/backend/InvenTree/InvenTree/api.py +++ b/src/backend/InvenTree/InvenTree/api.py @@ -1,6 +1,9 @@ """Main JSON interface views.""" +import json +import logging import sys +from pathlib import Path from django.conf import settings from django.db import transaction @@ -31,6 +34,60 @@ from .status import check_system_health, is_worker_running from .version import inventreeApiText 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): """Serializer for a single version.""" diff --git a/src/backend/InvenTree/InvenTree/api_version.py b/src/backend/InvenTree/InvenTree/api_version.py index 8d2c02ccfe..a2f40c6ec7 100644 --- a/src/backend/InvenTree/InvenTree/api_version.py +++ b/src/backend/InvenTree/InvenTree/api_version.py @@ -1,11 +1,14 @@ """InvenTree API version information.""" # 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.""" 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 - Remove /plugin/activate endpoint - Update docstrings and typing for various API endpoints (no functional changes) diff --git a/src/backend/InvenTree/InvenTree/urls.py b/src/backend/InvenTree/InvenTree/urls.py index 6f007a084a..a3f57df1d5 100644 --- a/src/backend/InvenTree/InvenTree/urls.py +++ b/src/backend/InvenTree/InvenTree/urls.py @@ -39,7 +39,14 @@ from stock.urls import stock_urls from web.urls import api_urls as web_api_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 .social_auth_urls import ( EmailListView, @@ -99,6 +106,7 @@ apipatterns = [ name='schema', ), # InvenTree information endpoints + path('license/', LicenseView.as_view(), name='api-license'), # license info path( 'version-text', VersionTextView.as_view(), name='api-version-text' ), # version text diff --git a/src/backend/requirements.in b/src/backend/requirements.in index 71de7fb8c9..b0ede62f5e 100644 --- a/src/backend/requirements.in +++ b/src/backend/requirements.in @@ -18,7 +18,7 @@ django-maintenance-mode # Shut down application while reloading django-markdownify # Markdown rendering django-mptt # Modified Preorder Tree Traversal 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-redis>=5.0.0 # Redis integration django-q2 # Background task scheduling @@ -41,6 +41,7 @@ gunicorn # Gunicorn web server pdf2image # PDF to image conversion pillow # Image manipulation 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-dotenv # Environment variable management pyyaml>=6.0.1 # YAML parsing diff --git a/src/backend/requirements.txt b/src/backend/requirements.txt index 8054e5d4cf..c8d9b33a20 100644 --- a/src/backend/requirements.txt +++ b/src/backend/requirements.txt @@ -96,7 +96,7 @@ django-js-asset==2.2.0 # via django-mptt django-maintenance-mode==0.21.1 django-markdownify==0.9.3 -django-money==3.4.1 +django-money==3.2.0 django-mptt==0.16.0 django-otp==1.3.0 # via django-allauth-2fa @@ -230,6 +230,9 @@ pillow==10.2.0 # qrcode # weasyprint pint==0.21 +pip-licenses==4.3.4 +prettytable==3.10.0 + # via pip-licenses protobuf==4.25.3 # via # googleapis-common-protos @@ -329,6 +332,8 @@ urllib3==2.2.1 # dulwich # requests # sentry-sdk +wcwidth==0.2.13 + # via prettytable weasyprint==61.2 # via django-weasyprint webencodings==0.5.1 diff --git a/src/frontend/package.json b/src/frontend/package.json index 8d72a69737..7f9f2809cd 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -65,6 +65,7 @@ "@types/react-router-dom": "^5.3.3", "@vitejs/plugin-react": "^4.2.1", "babel-plugin-macros": "^3.1.0", + "rollup-plugin-license": "^3.3.1", "nyc": "^15.1.0", "typescript": "^5.3.3", "vite": "^5.2.7", diff --git a/src/frontend/src/components/modals/LicenseModal.tsx b/src/frontend/src/components/modals/LicenseModal.tsx new file mode 100644 index 0000000000..05c8d4a79c --- /dev/null +++ b/src/frontend/src/components/modals/LicenseModal.tsx @@ -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) { + return ( + + + {entries?.length > 0 && ( + + {entries?.map((entry: any, index: number) => ( + + + + {entry.name} + {entry.license} + + {entry.version} + + + + {entry.licensetext || t`No license text available`} + + + ))} + + )} + + ); +} + +export function LicenseModal() { + const { data, isFetching, isError } = useQuery({ + queryKey: ['license'], + queryFn: () => + api + .get(apiUrl(ApiEndpoints.license)) + .then((res) => res.data ?? {}) + .catch(() => {}) + }); + + return ( + + + + {isFetching && ( + + Loading license information + + )} + {isError ? ( + + + Failed to fetch license information + + + ) : ( + + + {Object.keys(data ?? {}).map((key) => ( + + {key} Packages + + ))} + + + {Object.keys(data ?? {}).map((key) => ( + + {LicenceView(data[key] ?? [])} + + ))} + + )} + + ); +} diff --git a/src/frontend/src/contexts/ThemeContext.tsx b/src/frontend/src/contexts/ThemeContext.tsx index b9ee5160b1..c973719f61 100644 --- a/src/frontend/src/contexts/ThemeContext.tsx +++ b/src/frontend/src/contexts/ThemeContext.tsx @@ -10,6 +10,7 @@ import { ModalsProvider } from '@mantine/modals'; import { Notifications } from '@mantine/notifications'; import { AboutInvenTreeModal } from '../components/modals/AboutInvenTreeModal'; +import { LicenseModal } from '../components/modals/LicenseModal'; import { QrCodeModal } from '../components/modals/QrCodeModal'; import { ServerInfoModal } from '../components/modals/ServerInfoModal'; import { useLocalState } from '../states/LocalState'; @@ -65,7 +66,8 @@ export function ThemeContext({ children }: { children: JSX.Element }) { modals={{ qr: QrCodeModal, info: ServerInfoModal, - about: AboutInvenTreeModal + about: AboutInvenTreeModal, + license: LicenseModal }} > {children} diff --git a/src/frontend/src/defaults/links.tsx b/src/frontend/src/defaults/links.tsx index ce0c782bfe..48f99e5b2f 100644 --- a/src/frontend/src/defaults/links.tsx +++ b/src/frontend/src/defaults/links.tsx @@ -96,8 +96,19 @@ function aboutInvenTree() { innerProps: {} }); } +function licenseInfo() { + return openContextModal({ + modal: 'license', + title: ( + + License Information + + ), + size: 'xl', + innerProps: {} + }); +} -// TODO @matmair: Add the following pages and adjust the links export const aboutLinks: DocumentationLinkItem[] = [ { id: 'instance', @@ -114,8 +125,7 @@ export const aboutLinks: DocumentationLinkItem[] = [ { id: 'licenses', title: Licenses, - description: Licenses for packages used by InvenTree, - link: '/licenses', - placeholder: true + description: Licenses for dependencies of the service, + action: licenseInfo } ]; diff --git a/src/frontend/src/enums/ApiEndpoints.tsx b/src/frontend/src/enums/ApiEndpoints.tsx index f0910099da..7911a0d9c7 100644 --- a/src/frontend/src/enums/ApiEndpoints.tsx +++ b/src/frontend/src/enums/ApiEndpoints.tsx @@ -40,6 +40,7 @@ export enum ApiEndpoints { news = 'news/', global_status = 'generic/status/', version = 'version/', + license = 'license/', sso_providers = 'auth/providers/', group_list = 'user/group/', owner_list = 'user/owner/', diff --git a/src/frontend/vite.config.ts b/src/frontend/vite.config.ts index 2fa09ea382..c5b58e384d 100644 --- a/src/frontend/vite.config.ts +++ b/src/frontend/vite.config.ts @@ -1,5 +1,6 @@ import react from '@vitejs/plugin-react'; import { platform, release } from 'node:os'; +import license from 'rollup-plugin-license'; import { defineConfig, splitVendorChunkPlugin } from 'vite'; import istanbul from 'vite-plugin-istanbul'; @@ -19,6 +20,19 @@ export default defineConfig({ } }), 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({ include: 'src/*', exclude: ['node_modules', 'test/'], diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock index 30201d8ed1..bba2af56a1 100644 --- a/src/frontend/yarn.lock +++ b/src/frontend/yarn.lock @@ -942,7 +942,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" 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" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== @@ -1769,6 +1769,11 @@ aria-hidden@^1.1.3: dependencies: 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: version "0.4.0" 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" 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: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -2481,7 +2491,7 @@ glob-parent@~5.1.0: dependencies: 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" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" 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" 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" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -2897,6 +2907,13 @@ lru-cache@^6.0.0: dependencies: 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: version "3.1.0" 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: 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: version "0.5.2" 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" 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: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -3514,6 +3546,21 @@ rimraf@^3.0.0: dependencies: 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: version "4.13.0" 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" 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: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" diff --git a/tasks.py b/tasks.py index 5cf0f25854..e43227b44a 100644 --- a/tasks.py +++ b/tasks.py @@ -244,6 +244,12 @@ def install(c, uv=False): # Run plugins install 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'}) def setup_dev(c, tests=False):