diff --git a/.git-hooks/pre-commit b/.git-hooks/pre-commit deleted file mode 100755 index 4c6c91173..000000000 --- a/.git-hooks/pre-commit +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env sh - -TOP_DIR="$(pwd)" -export TOP_DIR - -if git diff --cached --name-only | grep "^client/" >/dev/null; then - cd client || exit - yarn install - yarn format && yarn syntax -else - printf "No changes in the client directory. Skipping pre-commit hook.\n\n" -fi - -cd "$TOP_DIR" || exit -if git diff --cached --name-only | grep "^servers/execution/runner/" >/dev/null; then - cd "servers/execution/runner" || exit - yarn install - yarn format && yarn syntax -else - printf "No changes in the servers/execution/runner directory. Skipping pre-commit hook.\n\n" -fi diff --git a/.git-hooks/pre-push b/.git-hooks/pre-push deleted file mode 100755 index cdf518ae5..000000000 --- a/.git-hooks/pre-push +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env sh - -BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD) -TOP_DIR="$(pwd)" -export TOP_DIR - -if git diff --name-only origin/"$BRANCH_NAME"...HEAD | grep "^client/" >/dev/null; then - cd client || exit - yarn install - yarn jest . --coverage=false -else - printf "No changes in the client directory. Skipping pre-push hook.\n\n" -fi - -cd "$TOP_DIR" || exit -if git diff --name-only origin/"$BRANCH_NAME"...HEAD | grep "^servers/execution/runner/" >/dev/null; then - cd "servers/execution/runner" || exit - yarn install - yarn test:nocov -else - printf "No changes in the servers/execution/runner/ directory. Skipping pre-push hook.\n\n" -fi diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 000000000..0b754b190 --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,7 @@ +default: true +MD033: false +MD013: + code_blocks: false + tables: true +MD046: + style: "fenced" \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..b9d4dfd6f --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,88 @@ +default_install_hook_types: [pre-commit, pre-push] + +repos: + - repo: local + hooks: + - id: yarn-install-client + name: yarn install client + entry: bash + language: system + files: "^client/.*" + args: ["-c", "cd client && yarn install"] + - id: yarn-install-runner + name: yarn install runner + entry: bash + language: system + files: "^servers/execution/runner/.*" + args: ["-c", "cd servers/execution/runner && yarn install"] + - id: yarn-install-lib + name: yarn install lib + entry: bash + language: system + files: "^servers/lib/.*" + args: ["-c", "cd servers/lib && yarn install"] + + - id: yarn-jest-client + name: yarn jest client + entry: bash + language: system + files: "^client/.*" + args: ["-c", "cd client && yarn jest . --coverage=false"] + stages: [pre-push] + - id: yarn-test-runner + name: yarn test runner + entry: bash + language: system + files: "^servers/execution/runner/.*" + args: ["-c", "cd servers/execution/runner && yarn test:nocov"] + stages: [pre-push] + # - id: yarn-test-lib + # name: yarn test lib + # entry: bash + # language: system + # files: "^servers/lib/.*" + # args: ["-c", "cd servers/lib && yarn jest . --coverage=false"] + # stages: [pre-push] + + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v3.1.0 + hooks: + - id: prettier + args: ["--ignore-path", "../.gitignore", "--write"] + files: '^(client|servers/execution/runner|servers/lib)/.*\.(ts|tsx|css|scss)$' + stages: [pre-commit] + + - repo: https://github.com/pre-commit/mirrors-eslint + rev: v8.54.0 + hooks: + - id: eslint + args: ["--fix"] + files: "^(client|servers/execution/runner|servers/lib)/.*" + stages: [pre-commit] + + - repo: https://github.com/igorshubovych/markdownlint-cli + rev: v0.37.0 + hooks: + - id: markdownlint + files: '.*\.md$' + entry: ./script/markdownlint-hook.sh + verbose: true + stages: [pre-commit] + + - repo: https://github.com/syntaqx/git-hooks + rev: v0.0.18 + hooks: + - id: shellcheck + files: '.*' + stages: [pre-commit] + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-json + files: '^(docs|deploy|script|ssl)/.*' + stages: [pre-commit] + - id: check-yaml + files: '^(docs|deploy|script|ssl)/.*' + stages: [pre-commit] + \ No newline at end of file diff --git a/client/.prettierrc b/client/.prettierrc new file mode 100644 index 000000000..a20502b7f --- /dev/null +++ b/client/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "trailingComma": "all" +} diff --git a/client/LICENSE.md b/client/LICENSE.md index c0ad1333c..c23748f41 100644 --- a/client/LICENSE.md +++ b/client/LICENSE.md @@ -20,10 +20,10 @@ * The INTO-CPS tool suite software and the INTO-CPS Association * Public License (ICAPL) are obtained from the INTO-CPS Association, either -* from the above address, from the URLs: http://www.into-cps.org or +* from the above address, from the URLs: or * in the INTO-CPS tool suite distribution. * GNU version 3 is obtained from: -* http://www.gnu.org/copyleft/gpl.html. +* . * This program is distributed WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS @@ -291,11 +291,11 @@ This Agreement is governed by the laws of Denmark. The place of jurisdiction for all disagreements related to this Agreement, is Aarhus, Denmark. The EPL 1.0 license definition has been obtained from: -http://www.eclipse.org/legal/epl-v10.html. +. It is also reproduced in the INTO-CPS distribution. The GPL Version 3 license definition has been obtained from -http://www.gnu.org/copyleft/gpl.html. +. It is also reproduced in the INTO-CPS distribution. --- End of Definition of INTO-CPS Association Public License --- diff --git a/client/public/static/css/MaterialIcon.css b/client/public/static/css/MaterialIcon.css index 5d7418a3f..6700ea0f1 100644 --- a/client/public/static/css/MaterialIcon.css +++ b/client/public/static/css/MaterialIcon.css @@ -4,7 +4,9 @@ font-family: 'Material Icons'; font-style: normal; font-weight: 400; - src: local('Material Icons'), local('MaterialIcons-Regular'), + src: + local('Material Icons'), + local('MaterialIcons-Regular'), url(/static/font/MaterialIcons-Regular.woff2) format('woff2'), url(/static/font/MaterialIcons-Regular.woff) format('woff'), url(/static/font/MaterialIcons-Regular.ttf) format('truetype'); diff --git a/client/public/static/font/README.md b/client/public/static/font/README.md deleted file mode 100644 index 7fa35e599..000000000 --- a/client/public/static/font/README.md +++ /dev/null @@ -1,22 +0,0 @@ -The recommended way to use the Material Icons font is by linking to the web font hosted on Google Fonts: - -```html - - - - - - - - - - - - -``` - - diff --git a/client/src/components/tab/TabComponent.tsx b/client/src/components/tab/TabComponent.tsx index bbcec27c2..6ce250893 100644 --- a/client/src/components/tab/TabComponent.tsx +++ b/client/src/components/tab/TabComponent.tsx @@ -24,7 +24,7 @@ function renderScopeTabList(scope: TabData[][], subIndex: number): JSX.Element { function renderScopeTabPanels( scope: TabData[][], - subIndex: number + subIndex: number, ): JSX.Element { return ( <> diff --git a/client/src/index.tsx b/client/src/index.tsx index 40b8c7369..7db8206ed 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -57,7 +57,7 @@ const router = createBrowserRouter( ], { basename: `/${useURLbasename()}`, - } + }, ); const root = document.getElementById('root'); @@ -68,7 +68,7 @@ if (root) { - + , ); } else { throw Error("Couldn't find root element"); diff --git a/client/src/route/library/Library.tsx b/client/src/route/library/Library.tsx index fd13c6b5e..75356056d 100644 --- a/client/src/route/library/Library.tsx +++ b/client/src/route/library/Library.tsx @@ -32,7 +32,7 @@ export function createCombinedTabs() { /> ), - })) + })), ); } diff --git a/client/test/README.md b/client/test/README.md index dd62cfd60..757a98621 100644 --- a/client/test/README.md +++ b/client/test/README.md @@ -182,4 +182,3 @@ yarn test -e This command launches the test runner and executes all end-to-end tests. Make sure you have an active internet connection while running these tests, as they simulate real user interactions with your GitLab account. - diff --git a/client/test/e2e/playwright/Auth.test.ts b/client/test/e2e/playwright/Auth.test.ts index fef1af43e..b7d555967 100644 --- a/client/test/e2e/playwright/Auth.test.ts +++ b/client/test/e2e/playwright/Auth.test.ts @@ -13,7 +13,7 @@ test.describe('Tests on Authentication Flow', () => { .getByRole('button', { name: 'GitLab logo Sign In with GitLab' }) .click(); await expect( - page.getByRole('button', { name: 'Open settings' }) + page.getByRole('button', { name: 'Open settings' }), ).toBeVisible(); await expect(page).toHaveURL(/.*Library/); }); @@ -23,7 +23,7 @@ test.describe('Tests on Authentication Flow', () => { .getByRole('button', { name: 'GitLab logo Sign In with GitLab' }) .click(); await expect( - page.getByRole('button', { name: 'Open settings' }) + page.getByRole('button', { name: 'Open settings' }), ).toBeVisible(); await expect(page).toHaveURL(/.*Library/); diff --git a/client/test/e2e/playwright/Menu.test.ts b/client/test/e2e/playwright/Menu.test.ts index 8f2cdc6a2..97ff3e193 100644 --- a/client/test/e2e/playwright/Menu.test.ts +++ b/client/test/e2e/playwright/Menu.test.ts @@ -10,7 +10,7 @@ test.describe('Menu Links from first page (Layout)', () => { .getByRole('button', { name: 'GitLab logo Sign In with GitLab' }) .click(); await expect( - page.getByRole('button', { name: 'Open settings' }) + page.getByRole('button', { name: 'Open settings' }), ).toBeVisible(); await expect(page).toHaveURL(/.*Library/); }); @@ -19,7 +19,7 @@ test.describe('Menu Links from first page (Layout)', () => { await links.reduce(async (previousPromise, link) => { await previousPromise; const linkElement = await page.locator( - `div[role="button"]:has-text("${link.text}")` + `div[role="button"]:has-text("${link.text}")`, ); await expect(linkElement).toBeVisible(); }, Promise.resolve()); diff --git a/client/test/e2e/playwright/auth.setup.ts b/client/test/e2e/playwright/auth.setup.ts index 723a16f73..a97468ae9 100644 --- a/client/test/e2e/playwright/auth.setup.ts +++ b/client/test/e2e/playwright/auth.setup.ts @@ -42,7 +42,7 @@ setup('authenticate', async ({ page }) => { // 'Authorize' button did not appear within 4 seconds, so just ignore and continue. } await expect( - page.getByRole('button', { name: 'Open settings' }) + page.getByRole('button', { name: 'Open settings' }), ).toBeVisible(); const storage = await page.context().storageState(); diff --git a/client/test/integration/authRedux.test.tsx b/client/test/integration/authRedux.test.tsx index 5eda40ab4..bd59bb3e6 100644 --- a/client/test/integration/authRedux.test.tsx +++ b/client/test/integration/authRedux.test.tsx @@ -49,7 +49,7 @@ const setupTest = (authState: AuthState) => { , - { route: '/private', store } + { route: '/private', store }, ); }; @@ -75,7 +75,7 @@ describe('Redux and Authentication integration test', () => { expect(screen.getByText('Signin')).toBeInTheDocument(); expect(authReducer(undefined, { type: 'unknown' })).toEqual( - initialState.auth + initialState.auth, ); expect(store.getState().userName).toBe(undefined); }); diff --git a/client/test/unitTests/Components/Linkbuttons.test.tsx b/client/test/unitTests/Components/Linkbuttons.test.tsx index 6a467b681..27952ee2c 100644 --- a/client/test/unitTests/Components/Linkbuttons.test.tsx +++ b/client/test/unitTests/Components/Linkbuttons.test.tsx @@ -24,7 +24,7 @@ const getButtonIcon = (key: string) => const evaluateButtonSize = (expectedSize: number) => { buttons.forEach((button) => { expect( - getComputedStyle(getButtonIcon(button.key)).getPropertyValue('font-size') + getComputedStyle(getButtonIcon(button.key)).getPropertyValue('font-size'), ).toBe(`${expectedSize}rem`); }); }; @@ -38,7 +38,7 @@ describe('LinkButtons component default size', () => { buttons.forEach((button) => { expect(getButton(button.key).parentElement).toHaveAttribute( 'aria-label', - button.link + button.link, ); expect(getLabel(button.key).tagName).toBe('H6'); }); @@ -66,7 +66,7 @@ describe('LinkButtons component default size', () => { it('should use name from iconLib as label when avaiable', () => { expect(getLabel(buttons[0].key).textContent).toBe( - LinkIcons[buttons[0].key].name + LinkIcons[buttons[0].key].name, ); }); }); diff --git a/client/test/unitTests/Components/PrivateRoute.test.tsx b/client/test/unitTests/Components/PrivateRoute.test.tsx index 962204e6a..25ae748d8 100644 --- a/client/test/unitTests/Components/PrivateRoute.test.tsx +++ b/client/test/unitTests/Components/PrivateRoute.test.tsx @@ -30,7 +30,7 @@ const setupTest = (authState: AuthState) => { , - { route: '/private' } + { route: '/private' }, ); }; diff --git a/client/test/unitTests/Components/TabComponent.test.tsx b/client/test/unitTests/Components/TabComponent.test.tsx index 0c1751da4..881c1683d 100644 --- a/client/test/unitTests/Components/TabComponent.test.tsx +++ b/client/test/unitTests/Components/TabComponent.test.tsx @@ -11,7 +11,7 @@ describe('TabComponent', () => { test('renders an empty tab', () => { const { getByText } = render( - + , ); const emptyTab = getByText('Functions'); expect(emptyTab).toBeInTheDocument(); @@ -60,10 +60,10 @@ describe('TabComponent', () => { } expect( - screen.queryByText(assetTypeTabs[0].body.props.children) + screen.queryByText(assetTypeTabs[0].body.props.children), ).not.toBeInTheDocument(); expect( - screen.queryByText(assetTypeTabs[1].body.props.children) + screen.queryByText(assetTypeTabs[1].body.props.children), ).not.toBeInTheDocument(); }); diff --git a/client/test/unitTests/Page/LayoutPublic.test.tsx b/client/test/unitTests/Page/LayoutPublic.test.tsx index 08e8e9e58..0af0b5e1e 100644 --- a/client/test/unitTests/Page/LayoutPublic.test.tsx +++ b/client/test/unitTests/Page/LayoutPublic.test.tsx @@ -11,7 +11,7 @@ const PublicTestComponentId = 'public-component'; describe('LayoutPublic component with one element', () => { beforeEach(() => - renderLayoutWithRouter(LayoutPublic, [PublicTestComponentId]) + renderLayoutWithRouter(LayoutPublic, [PublicTestComponentId]), ); basicLayoutTestsWithSingleComponent(); diff --git a/client/test/unitTests/Page/page.testUtils.tsx b/client/test/unitTests/Page/page.testUtils.tsx index 631a5a555..2cca112b3 100644 --- a/client/test/unitTests/Page/page.testUtils.tsx +++ b/client/test/unitTests/Page/page.testUtils.tsx @@ -7,7 +7,7 @@ export const TestComponentIdList = ['component1', 'component2', 'component3']; export function renderLayoutWithRouter( Layout: (props: { children: React.ReactElement[] }) => React.ReactElement, - Children: string[] + Children: string[], ) { render({generateTestDivs(Children)}, { wrapper: BrowserRouter, diff --git a/client/test/unitTests/Routes/Library.test.tsx b/client/test/unitTests/Routes/Library.test.tsx index 1aaf87268..81fea8a8c 100644 --- a/client/test/unitTests/Routes/Library.test.tsx +++ b/client/test/unitTests/Routes/Library.test.tsx @@ -19,7 +19,7 @@ describe('Library with no props', () => { InitRouteTests( - + , ); itDisplaysContentOfTabs(assetType); diff --git a/client/test/unitTests/Routes/SignIn.test.tsx b/client/test/unitTests/Routes/SignIn.test.tsx index 5a097ef7d..e53d8f66d 100644 --- a/client/test/unitTests/Routes/SignIn.test.tsx +++ b/client/test/unitTests/Routes/SignIn.test.tsx @@ -23,11 +23,11 @@ describe('SignIn', () => { render( - + , ); expect( - screen.getByRole('button', { name: /Sign In With GitLab/i }) + screen.getByRole('button', { name: /Sign In With GitLab/i }), ).toBeInTheDocument(); }); @@ -35,7 +35,7 @@ describe('SignIn', () => { render( - + , ); const signInButton = screen.getByRole('button', { diff --git a/client/test/unitTests/Util/Store.test.ts b/client/test/unitTests/Util/Store.test.ts index b17c981f6..dd638a44c 100644 --- a/client/test/unitTests/Util/Store.test.ts +++ b/client/test/unitTests/Util/Store.test.ts @@ -25,7 +25,7 @@ describe('reducers', () => { describe('menu reducer', () => { const itShouldHandleMenuActions = ( actionCreator: () => { type: string }, - expectedValue: boolean + expectedValue: boolean, ) => { const newState = menuReducer(initialState.menu, actionCreator()); expect(newState.isOpen).toBe(expectedValue); @@ -33,7 +33,7 @@ describe('reducers', () => { it('menuReducer should return the initial menu state when an unknown action type is passed with an undefined state', () => { expect(menuReducer(undefined, { type: 'unknown' })).toEqual( - initialState.menu + initialState.menu, ); }); @@ -50,7 +50,7 @@ describe('reducers', () => { describe('auth reducer', () => { it('authReducer should return the initial menu state when an unknown action type is passed with an undefined state', () => { expect(authReducer(undefined, { type: 'unknown' })).toEqual( - initialState.auth + initialState.auth, ); }); diff --git a/client/test/unitTests/Util/envUtil.test.ts b/client/test/unitTests/Util/envUtil.test.ts index 75f937147..1c0edf925 100644 --- a/client/test/unitTests/Util/envUtil.test.ts +++ b/client/test/unitTests/Util/envUtil.test.ts @@ -53,10 +53,10 @@ describe('envUtil', () => { test('GetURL should return the correct enviroment variables', () => { expect(useURLforDT()).toBe( - `${testAppURL}/${testBasename}/${testUsername}/${testDT}` + `${testAppURL}/${testBasename}/${testUsername}/${testDT}`, ); expect(useURLforLIB()).toBe( - `${testAppURL}/${testBasename}/${testUsername}/${testLIB}` + `${testAppURL}/${testBasename}/${testUsername}/${testLIB}`, ); expect(useURLbasename()).toBe(testBasename); }); @@ -71,8 +71,8 @@ describe('envUtil', () => { const result = getWorkbenchLinkValues(); expect( result.every( - (el) => typeof el.key === 'string' && typeof el.link === 'string' - ) + (el) => typeof el.key === 'string' && typeof el.link === 'string', + ), ).toBe(true); }); @@ -83,8 +83,8 @@ describe('envUtil', () => { result.forEach((el, i) => { expect(el.link).toEqual( `${testAppURL}/${testBasename}/${testUsername}/${cleanURL( - testWorkbenchEndpoints[i] - )}` + testWorkbenchEndpoints[i], + )}`, ); }); }); diff --git a/client/test/unitTests/auth/AuthProvider.test.tsx b/client/test/unitTests/auth/AuthProvider.test.tsx index 14ca5e93b..87d7803c6 100644 --- a/client/test/unitTests/auth/AuthProvider.test.tsx +++ b/client/test/unitTests/auth/AuthProvider.test.tsx @@ -38,7 +38,7 @@ describe('AuthProvider', () => { const { getByText } = renderAuthProvider(); expect( - getByText('Authentication service unavailable...try again later') + getByText('Authentication service unavailable...try again later'), ).toBeInTheDocument(); }); diff --git a/client/test/unitTests/testUtils.tsx b/client/test/unitTests/testUtils.tsx index 295a654ea..c4a95534b 100644 --- a/client/test/unitTests/testUtils.tsx +++ b/client/test/unitTests/testUtils.tsx @@ -18,7 +18,7 @@ type RouterOptions = { export const renderWithRouter = ( ui: React.ReactElement, - { route = '/', store }: RouterOptions = {} + { route = '/', store }: RouterOptions = {}, ) => { window.history.pushState({}, 'Test page', route); @@ -26,7 +26,7 @@ export const renderWithRouter = ( ? render( - + , ) : render(); }; @@ -65,7 +65,7 @@ export function InitRouteTests(component: React.ReactElement) { } export function itDisplaysContentOfTabs( - tabs: { label: string; body: string }[] + tabs: { label: string; body: string }[], ) { it('should render labels of all tabs', () => { tabs.forEach((tab) => { @@ -117,7 +117,7 @@ export interface TabLabelURLPair { } export function itHasCorrectURLOfTabsWithIframe( - tablabelsURLpair: TabLabelURLPair[] + tablabelsURLpair: TabLabelURLPair[], ) { it('should render the Iframe component for the first tab with the correct title and URL', () => { tablabelsURLpair.forEach((tablabelURLpair) => { diff --git a/docs/developer/index.md b/docs/developer/index.md index 4db623d3d..ba888b565 100644 --- a/docs/developer/index.md +++ b/docs/developer/index.md @@ -22,6 +22,16 @@ The git-hooks will ensure that your commits are formatted correctly and that the tests pass before you push the commits to remote repositories. +You can also run the git-hooks manually before committing or pushing +by using the run commands below. The autoupdate command will set the +revisions of the git repos used in the .pre-commit-config.yaml up to date. + +```bash +pre-commit run --hook-stage pre-commit # runs format and syntax checks +pre-commit run --hook-stage pre-push # runs test +pre-commit autoupdate # update hooks to latests versions +``` + Be aware that the tests may take a long time to run. If you want to skip the tests or formatting, you can use the `--no-verify` flag @@ -77,11 +87,11 @@ the code quality. The project code qualities are measured based on: -* Linting issues identified by +- Linting issues identified by [Code Climate](https://codeclimate.com/github/INTO-CPS-Association/DTaaS) -* Test coverage report collected by +- Test coverage report collected by [Codecov](https://codecov.io/gh/INTO-CPS-Association/DTaaS) -* Successful [github actions](https://github.com/INTO-CPS-Association/DTaaS/actions) +- Successful [github actions](https://github.com/INTO-CPS-Association/DTaaS/actions) ### Code Climate diff --git a/script/configure-git-hooks.sh b/script/configure-git-hooks.sh index 723d05bb5..67e2e860c 100755 --- a/script/configure-git-hooks.sh +++ b/script/configure-git-hooks.sh @@ -1,4 +1,6 @@ #!/bin/sh -git config --local core.hooksPath .git-hooks -printf "Git hooks configured successfully. See .git-hooks for more information." +pip install pre-commit +pre-commit install + +printf "Git hooks setup successfully. See .git/hooks/ for more information." diff --git a/script/docs.sh b/script/docs.sh index 252ec3ec3..4978519a6 100755 --- a/script/docs.sh +++ b/script/docs.sh @@ -13,7 +13,7 @@ COMMIT_HASH=$(git rev-parse --short HEAD) export COMMIT_HASH export MKDOCS_ENABLE_PDF_EXPORT=1 -echo ${VERSION} +echo "${VERSION}" if [ -d site ] then rm -rf site diff --git a/script/env.sh b/script/env.sh index e875e1c3c..2c1e71b16 100755 --- a/script/env.sh +++ b/script/env.sh @@ -22,6 +22,10 @@ sudo -H pip3 install qrcode sudo apt-get install -y rubygems sudo gem install mdl +# Install shellcheck +sudo apt-get install -y shellcheck + # Install madge for generating dependency graphs of typescript projects sudo apt-get install -y graphviz -sudo npm install -g madge \ No newline at end of file +sudo npm install -g madge + diff --git a/script/markdownlint-hook.sh b/script/markdownlint-hook.sh new file mode 100755 index 000000000..7c63ed5e8 --- /dev/null +++ b/script/markdownlint-hook.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# This script is used by the pre-commit hook to check the markdown files without exiting the commit process. +output=$(markdownlint "$@") +echo "$output" +exit 0 \ No newline at end of file diff --git a/servers/execution/runner/LICENSE.md b/servers/execution/runner/LICENSE.md index 5e134141b..6c0f1294f 100644 --- a/servers/execution/runner/LICENSE.md +++ b/servers/execution/runner/LICENSE.md @@ -21,10 +21,10 @@ * The INTO-CPS tool suite software and the INTO-CPS Association * Public License (ICAPL) are obtained from the INTO-CPS Association, either * from the above address, from the URLs: -* http://www.into-cps.org or +* or * in the INTO-CPS tool suite distribution. * GNU version 3 is obtained from: -* http://www.gnu.org/copyleft/gpl.html. +* . * This program is distributed WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS @@ -298,11 +298,11 @@ This Agreement is governed by the laws of Denmark. The place of jurisdiction for all disagreements related to this Agreement, is Aarhus, Denmark. The EPL 1.0 license definition has been obtained from: -http://www.eclipse.org/legal/epl-v10.html. +. It is also reproduced in the INTO-CPS distribution. The GPL Version 3 license definition has been obtained from -http://www.gnu.org/copyleft/gpl.html. +. It is also reproduced in the INTO-CPS distribution. --- End of Definition of INTO-CPS Association Public License --- diff --git a/servers/execution/runner/README.md b/servers/execution/runner/README.md index 959270e5f..c0cb8434a 100644 --- a/servers/execution/runner/README.md +++ b/servers/execution/runner/README.md @@ -22,14 +22,14 @@ One digital twin runner is responsible for execution of a digital twin. ```bash yarn install # Install dependencies for the microservice -yarn syntax # analyzes source code for potential errors, style violations, and other issues, -yarn graph # generate dependency graphs in the code -yarn build # compile ES6 files into ES5 javascript files and copy all JS files into build/ directory -yarn test # run tests -yarn test:nocov # run the tests but do not report coverage -yarn test:watchAll #Watch changes in test/ and run the tests -yarn start # start the application -yarn clean # deletes directories "build", "coverage", and "dist" +yarn syntax # Analyze code for errors and style issues +yarn graph # Generate dependency graphs in the code +yarn build # Compile ES6 to ES5 and copy JS files to build/ directory +yarn test # Run tests +yarn test:nocov # Run the tests but do not report coverage +yarn test:watchAll # Watch changes in test/ and run the tests +yarn start # Start the application +yarn clean # Deletes directories "build", "coverage", and "dist" ``` ## :package: :ship: NPM package @@ -37,16 +37,16 @@ yarn clean # deletes directories "build", "coverage", and "dist" ### Github Package Registry The Github actions workflow of -[lib microservice](../../../.github/workflows/runner.yml) publishes the __runner__ +[lib microservice](../../../.github/workflows/runner.yml) publishes the **runner** into [public packages](https://github.com/orgs/INTO-CPS-Association/packages). ### Verdaccio - Local Package Registry Use the instructions in [publish npm package](../../../docs/developer/npm-packages.md) for help -with publishing __runner npm package__. +with publishing **runner npm package**. -Application of the advice given on that page for __runner__ will require +Application of the advice given on that page for **runner** will require running the following commands. ### Publish @@ -54,8 +54,8 @@ running the following commands. ```bash yarn install yarn build #the dist/ directory is needed for publishing step -yarn publish --no-git-tag-version #increments version in package.json, publishes to registry -yarn publish #increments version in package.json, publishes to registry and adds a git tag +yarn publish --no-git-tag-version #increments version and publishes to registry +yarn publish #increments version, publishes to registry and adds a git tag ``` ### Unpublish @@ -81,11 +81,11 @@ Access to the service on network is available at `http://:3000/` Two REST API routes are active. The route paths and the responses given for these two sources are: -| REST API Route | Return Value | Comment | -|:---|:---|:---| -| localhost:3000/phase | [ hello ] | The array get appended with each invocation. All the elements of are _array_. | -| localhost:3000/lifecycle/phase | _true_ | Always returns _true_ | -||| +| REST API Route | Return Value | Comment | +| :----------------------------- | :----------- | :------ | +| localhost:3000/phase | [ hello ] | Each invocation appends to _array_. | +| localhost:3000/lifecycle/phase | _true_ | Always returns _true_ | +| localhost:3000/phase | [ hello ] | array. | ## :balance_scale: License diff --git a/servers/lib/.prettierrc b/servers/lib/.prettierrc new file mode 100644 index 000000000..a20502b7f --- /dev/null +++ b/servers/lib/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "trailingComma": "all" +} diff --git a/servers/lib/DEVELOPER.md b/servers/lib/DEVELOPER.md index 05b195732..186e72dbb 100644 --- a/servers/lib/DEVELOPER.md +++ b/servers/lib/DEVELOPER.md @@ -9,16 +9,17 @@ file. Please see [README](./README.md) for this information. ```bash yarn install # Install dependencies for the microservice -yarn syntax # analyzes source code for potential errors, style violations, and other issues, -yarn graph # generate dependency graphs in the code -yarn build # compile ES6 files into ES5 javascript files and copy them into dist/ directory -yarn test -a # run all tests -yarn test -e # run end-to-end tests -yarn test -i # run integration tests -yarn test -u # run unit tests -yarn start # start the application -yarn start -h # list of all the CLI commands -yarn clean # deletes directories "build", "coverage", and "dist" +yarn syntax # Analyze code for errors and style issues +yarn graph # Generate dependency graphs in the code +yarn build # Compile ES6 to ES5 and copy JS files to build/ directory +yarn test -a # Run all tests +yarn test -e # Run end-to-end tests +yarn test -i # Run integration tests +yarn test -u # Run unit tests +yarn start # Start the application +yarn start -h # List of all the CLI commands +yarn start # Start the application +yarn clean # Deletes directories "build", "coverage", and "dist" ``` ## :package: :ship: NPM package @@ -43,8 +44,8 @@ running the following commands. ```bash yarn install yarn build #the dist/ directory is needed for publishing step -yarn publish --no-git-tag-version #increments version in package.json, publishes to registry -yarn publish #increments version in package.json, publishes to registry and adds a git tag +yarn publish --no-git-tag-version #increments version and publishes to registry +yarn publish #increments version, publishes to registry and adds a git tag ``` ### Unpublish diff --git a/servers/lib/LICENSE.md b/servers/lib/LICENSE.md index a5273233f..35c64b619 100644 --- a/servers/lib/LICENSE.md +++ b/servers/lib/LICENSE.md @@ -21,10 +21,10 @@ * The INTO-CPS tool suite software and the INTO-CPS Association * Public License (ICAPL) are obtained from the INTO-CPS Association, either * from the above address, from the URLs: -* http://www.into-cps.org or +* or * in the INTO-CPS tool suite distribution. * GNU version 3 is obtained from: -* http://www.gnu.org/copyleft/gpl.html. +* . * This program is distributed WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS @@ -293,11 +293,11 @@ This Agreement is governed by the laws of Denmark. The place of jurisdiction for all disagreements related to this Agreement, is Aarhus, Denmark. The EPL 1.0 license definition has been obtained from: -http://www.eclipse.org/legal/epl-v10.html. +. It is also reproduced in the INTO-CPS distribution. The GPL Version 3 license definition has been obtained from -http://www.gnu.org/copyleft/gpl.html. +. It is also reproduced in the INTO-CPS distribution. --- End of Definition of INTO-CPS Association Public License --- diff --git a/servers/lib/README.md b/servers/lib/README.md index 1e9bab981..4dfb10ce0 100644 --- a/servers/lib/README.md +++ b/servers/lib/README.md @@ -33,6 +33,7 @@ Set the registry and install the package with the following commands ```bash sudo npm config set @into-cps-association:registry https://npm.pkg.github.com +>>>>>>> origin/feature/distributed-demo sudo npm install -g @into-cps-association/libms ``` @@ -88,16 +89,16 @@ Display help. libms -h ``` -The config is saved `.env` file by convention. The __libms__ looks for +The config is saved `.env` file by convention. The **libms** looks for `.env` file in the working directory from which it is run. -If you want to run __libms__ without explicitly specifying the configuration +If you want to run **libms** without explicitly specifying the configuration file, run ```bash libms ``` -To run __libms__ with a custom config file, +To run **libms** with a custom config file, ```bash libms -c FILE-PATH @@ -113,6 +114,7 @@ libms -c ".env.development" You can press `Ctl+C` to halt the application. -The microservice is available at: http://localhost:PORT/lib +The microservice is available at: 'localhost:PORT/lib' + The [API](https://into-cps-association.github.io/DTaaS/development/user/servers/lib/LIB-MS.html) page shows sample queries and responses. diff --git a/servers/lib/package.json b/servers/lib/package.json index 53a0477f2..6c856f270 100644 --- a/servers/lib/package.json +++ b/servers/lib/package.json @@ -13,6 +13,7 @@ "scripts": { "build": "script/build.bash", "clean": "script/clean.bash", + "format": "prettier --ignore-path ../.gitignore --write \"**/*.{ts,tsx,css,scss}\"", "start": "script/start.bash", "syntax": "script/syntax.bash", "test": "script/test.bash", diff --git a/servers/lib/src/app.module.ts b/servers/lib/src/app.module.ts index 851febdf4..4a6893e3f 100644 --- a/servers/lib/src/app.module.ts +++ b/servers/lib/src/app.module.ts @@ -1,25 +1,24 @@ -import { ConfigModule, ConfigService } from "@nestjs/config"; -import { Module } from "@nestjs/common"; -import { GraphQLModule } from "@nestjs/graphql"; -import { ApolloDriver } from "@nestjs/apollo"; -import { join } from "path"; -import FilesModule from "./files/files.module"; +import { ConfigModule, ConfigService } from '@nestjs/config'; +import { Module } from '@nestjs/common'; +import { GraphQLModule } from '@nestjs/graphql'; +import { ApolloDriver } from '@nestjs/apollo'; +import { join } from 'path'; +import FilesModule from './files/files.module'; @Module({ imports: [ ConfigModule.forRoot({ - isGlobal: true + isGlobal: true, }), GraphQLModule.forRootAsync({ driver: ApolloDriver, useFactory: (configService: ConfigService) => ({ autoSchemaFile: join(process.cwd(), 'src/schema.gql'), - path: configService.get("APOLLO_PATH") + path: configService.get('APOLLO_PATH'), }), - inject: [ConfigService] + inject: [ConfigService], }), FilesModule, - ] + ], }) - export default class AppModule {} diff --git a/servers/lib/src/bootstrap.ts b/servers/lib/src/bootstrap.ts index 217c088bf..3924622be 100644 --- a/servers/lib/src/bootstrap.ts +++ b/servers/lib/src/bootstrap.ts @@ -1,26 +1,29 @@ -import { NestFactory } from "@nestjs/core"; -import { ConfigService } from "@nestjs/config"; -import * as dotenv from "dotenv" -import AppModule from "./app.module"; +import { NestFactory } from '@nestjs/core'; +import { ConfigService } from '@nestjs/config'; +import * as dotenv from 'dotenv'; +import AppModule from './app.module'; type BootstrapOptions = { - config?: string - runHelp?: CallableFunction -} + config?: string; + runHelp?: CallableFunction; +}; export default async function bootstrap(options?: BootstrapOptions) { - const configFile = dotenv.config({path: options?.config ?? ".env", override: true}) + const configFile = dotenv.config({ + path: options?.config ?? '.env', + override: true, + }); if (configFile.error) { // eslint-disable-next-line no-console console.error(configFile.error); if (options.runHelp) { - options.runHelp() + options.runHelp(); } else { - process.exit(1) + process.exit(1); } - }; + } const app = await NestFactory.create(AppModule); const configService = app.get(ConfigService); - const port = configService.get("PORT"); + const port = configService.get('PORT'); await app.listen(port); } diff --git a/servers/lib/src/files/files.module.ts b/servers/lib/src/files/files.module.ts index d1463d83d..f051c9dd1 100644 --- a/servers/lib/src/files/files.module.ts +++ b/servers/lib/src/files/files.module.ts @@ -1,8 +1,8 @@ -import { Module } from "@nestjs/common"; -import FilesResolver from "./resolvers/files.resolver"; -import GitlabFilesService from "./services/gitlab-files.service"; -import FilesServiceFactory from "./services/files-service.factory"; -import LocalFilesService from "./services/local-files.service"; +import { Module } from '@nestjs/common'; +import FilesResolver from './resolvers/files.resolver'; +import GitlabFilesService from './services/gitlab-files.service'; +import FilesServiceFactory from './services/files-service.factory'; +import LocalFilesService from './services/local-files.service'; @Module({ providers: [ diff --git a/servers/lib/src/files/interfaces/files.service.interface.ts b/servers/lib/src/files/interfaces/files.service.interface.ts index 19d280850..c2aa56fe3 100644 --- a/servers/lib/src/files/interfaces/files.service.interface.ts +++ b/servers/lib/src/files/interfaces/files.service.interface.ts @@ -1,4 +1,4 @@ -import { Project } from "src/types"; +import { Project } from 'src/types'; // FileService interface export interface IFilesService { diff --git a/servers/lib/src/files/resolvers/files.resolver.ts b/servers/lib/src/files/resolvers/files.resolver.ts index bfd7a7471..bf323d05e 100644 --- a/servers/lib/src/files/resolvers/files.resolver.ts +++ b/servers/lib/src/files/resolvers/files.resolver.ts @@ -1,7 +1,7 @@ -import { Resolver, Query, Args } from "@nestjs/graphql"; -import { IFilesService } from "../interfaces/files.service.interface"; -import FilesServiceFactory from "../services/files-service.factory"; -import { Project } from "../../types"; +import { Resolver, Query, Args } from '@nestjs/graphql'; +import { IFilesService } from '../interfaces/files.service.interface'; +import FilesServiceFactory from '../services/files-service.factory'; +import { Project } from '../../types'; @Resolver() export default class FilesResolver { @@ -12,12 +12,12 @@ export default class FilesResolver { } @Query(() => Project) - async listDirectory(@Args("path") path: string): Promise { + async listDirectory(@Args('path') path: string): Promise { return this.filesService.listDirectory(path); } @Query(() => Project) - async readFile(@Args("path") path: string): Promise { + async readFile(@Args('path') path: string): Promise { return this.filesService.readFile(path); } } diff --git a/servers/lib/src/files/services/files-service.factory.ts b/servers/lib/src/files/services/files-service.factory.ts index 80d2f96f9..72147e8e6 100644 --- a/servers/lib/src/files/services/files-service.factory.ts +++ b/servers/lib/src/files/services/files-service.factory.ts @@ -1,8 +1,8 @@ -import { Injectable, Inject } from "@nestjs/common"; -import { ConfigService } from "@nestjs/config"; -import { IFilesService } from "../interfaces/files.service.interface"; -import GitlabFilesService from "./gitlab-files.service"; -import LocalFilesService from "./local-files.service"; +import { Injectable, Inject } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { IFilesService } from '../interfaces/files.service.interface'; +import GitlabFilesService from './gitlab-files.service'; +import LocalFilesService from './local-files.service'; @Injectable() export default class FilesServiceFactory { @@ -10,18 +10,18 @@ export default class FilesServiceFactory { constructor( private configService: ConfigService, @Inject(GitlabFilesService) private gitlabFilesService: GitlabFilesService, - @Inject(LocalFilesService) private localFilesService: LocalFilesService + @Inject(LocalFilesService) private localFilesService: LocalFilesService, ) {} /* eslint-enable no-useless-constructor, no-empty-function */ - + create(): IFilesService { - const mode = this.configService.get("MODE"); - if (mode === "local") { + const mode = this.configService.get('MODE'); + if (mode === 'local') { return this.localFilesService; - } if (mode === "gitlab") { + } + if (mode === 'gitlab') { return this.gitlabFilesService; - } - throw new Error(`Invalid MODE: ${mode}`); - + } + throw new Error(`Invalid MODE: ${mode}`); } } diff --git a/servers/lib/src/files/services/gitlab-files.service.ts b/servers/lib/src/files/services/gitlab-files.service.ts index f0d81a63f..590889aa8 100644 --- a/servers/lib/src/files/services/gitlab-files.service.ts +++ b/servers/lib/src/files/services/gitlab-files.service.ts @@ -1,9 +1,9 @@ -import { Injectable } from "@nestjs/common"; -import { ConfigService } from "@nestjs/config"; -import axios from "axios"; -import { Project } from "src/types"; -import { IFilesService } from "../interfaces/files.service.interface"; -import { getDirectoryQuery, getReadFileQuery } from "../queries"; +import { Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import axios from 'axios'; +import { Project } from 'src/types'; +import { IFilesService } from '../interfaces/files.service.interface'; +import { getDirectoryQuery, getReadFileQuery } from '../queries'; type QueryFunction = (domain: string, parsedPath: string) => string; @@ -21,28 +21,28 @@ export default class GitlabFilesService implements IFilesService { } private async parseArguments( - path: string + path: string, ): Promise<{ domain: string; parsedPath: string }> { - const gitlabGroup = this.configService.get("GITLAB_GROUP"); - const pathParts: string[] = path.split("/"); + const gitlabGroup = this.configService.get('GITLAB_GROUP'); + const pathParts: string[] = path.split('/'); const project: string = pathParts[0]; // Only prepend the gitlabGroup if it's not already part of the path const domain: string = - project === gitlabGroup ? project : `${gitlabGroup }/${ project}`; + project === gitlabGroup ? project : `${gitlabGroup}/${project}`; - const parsedPath = pathParts.slice(1).join("/"); + const parsedPath = pathParts.slice(1).join('/'); return { domain, parsedPath }; } private async sendRequest(query: string): Promise { try { const response = await axios({ - url: "https://gitlab.com/api/graphql", - method: "post", + url: 'https://gitlab.com/api/graphql', + method: 'post', headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${this.configService.get("GITLAB_TOKEN")}`, + 'Content-Type': 'application/json', + Authorization: `Bearer ${this.configService.get('GITLAB_TOKEN')}`, }, data: { query, @@ -50,13 +50,13 @@ export default class GitlabFilesService implements IFilesService { }); return response.data.data.project; } catch (error) { - throw new Error("Invalid query"); // Throw error instead of returning string + throw new Error('Invalid query'); // Throw error instead of returning string } } private async executeQuery( path: string, - getQuery: QueryFunction + getQuery: QueryFunction, ): Promise { const { domain, parsedPath } = await this.parseArguments(path); const query = getQuery(domain, parsedPath); diff --git a/servers/lib/src/files/services/local-files.service.ts b/servers/lib/src/files/services/local-files.service.ts index dac1f2433..cda4e7744 100644 --- a/servers/lib/src/files/services/local-files.service.ts +++ b/servers/lib/src/files/services/local-files.service.ts @@ -1,31 +1,31 @@ -import { Injectable, InternalServerErrorException } from "@nestjs/common"; -import * as fs from "fs"; -import { join } from "path"; -import { ConfigService } from "@nestjs/config"; -import { Project } from "src/types"; -import { IFilesService } from "../interfaces/files.service.interface"; +import { Injectable, InternalServerErrorException } from '@nestjs/common'; +import * as fs from 'fs'; +import { join } from 'path'; +import { ConfigService } from '@nestjs/config'; +import { Project } from 'src/types'; +import { IFilesService } from '../interfaces/files.service.interface'; @Injectable() export default class LocalFilesService implements IFilesService { - // eslint-disable-next-line no-useless-constructor, no-empty-function + // eslint-disable-next-line no-useless-constructor, no-empty-function constructor(private configService: ConfigService) {} async listDirectory(path: string): Promise { - const dataPath = this.configService.get("LOCAL_PATH"); + const dataPath = this.configService.get('LOCAL_PATH'); const fullPath = join(dataPath, path); const files = await fs.promises.readdir(fullPath); const edges = await Promise.all( - files.map((file) => LocalFilesService.getFileStats(fullPath, file)) + files.map((file) => LocalFilesService.getFileStats(fullPath, file)), ); const tree = { trees: { - edges: edges.filter((edge) => edge.node.type === "tree"), + edges: edges.filter((edge) => edge.node.type === 'tree'), }, blobs: { - edges: edges.filter((edge) => edge.node.type === "blob"), + edges: edges.filter((edge) => edge.node.type === 'blob'), }, }; @@ -33,29 +33,28 @@ export default class LocalFilesService implements IFilesService { } async readFile(path: string): Promise { - const dataPath = this.configService.get("LOCAL_PATH"); + const dataPath = this.configService.get('LOCAL_PATH'); const fullpath = join(dataPath, path); try { const content = await ( - await fs.promises.readFile(fullpath, "utf8") + await fs.promises.readFile(fullpath, 'utf8') ).trim(); - const name = path.split("/").pop(); // extract file name from the path + const name = path.split('/').pop(); // extract file name from the path return LocalFilesService.formatResponse(name, content); } catch (error) { - throw new InternalServerErrorException("Error reading file"); + throw new InternalServerErrorException('Error reading file'); } } private static async getFileStats(fullPath: string, file: string) { const stats = await fs.promises.lstat(join(fullPath, file)); if (stats.isDirectory()) { - return { node: { name: file, type: "tree" } }; - } - return { node: { name: file, type: "blob" } }; - + return { node: { name: file, type: 'tree' } }; + } + return { node: { name: file, type: 'blob' } }; } private static formatResponse(name: string, content: string): Project { diff --git a/servers/lib/src/main.ts b/servers/lib/src/main.ts index b33395ab6..2c98d334d 100644 --- a/servers/lib/src/main.ts +++ b/servers/lib/src/main.ts @@ -1,25 +1,27 @@ #!/usr/bin/env node -import { Command } from "commander"; -import bootstrap from "./bootstrap"; +import { Command } from 'commander'; +import bootstrap from './bootstrap'; type ProgramOptions = { - config?: string -} + config?: string; +}; const program = new Command(); program - .description("The lib microservice is responsible for handling and serving the contents of library assets of the DTaaS platform. It provides API endpoints for clients to query, and fetch these assets.") - .option('-c, --config ', "set the config path (default .env)") - .helpOption('-h, --help', 'display help for libms') - .showHelpAfterError(); - + .description( + 'The lib microservice is responsible for handling and serving the contents of library assets of the DTaaS platform. It provides API endpoints for clients to query, and fetch these assets.', + ) + .option('-c, --config ', 'set the config path (default .env)') + .helpOption('-h, --help', 'display help for libms') + .showHelpAfterError(); + program.parse(process.argv); const options: ProgramOptions = program.opts(); -if (options.config) { - bootstrap({config: options.config, runHelp: () => program.help()}) +if (options.config) { + bootstrap({ config: options.config, runHelp: () => program.help() }); } else { - bootstrap({runHelp: () => program.help()}); + bootstrap({ runHelp: () => program.help() }); } diff --git a/servers/lib/src/types.ts b/servers/lib/src/types.ts index 7fc2111ae..afc5ddf43 100644 --- a/servers/lib/src/types.ts +++ b/servers/lib/src/types.ts @@ -1,4 +1,4 @@ -import { Field, ObjectType } from "@nestjs/graphql"; +import { Field, ObjectType } from '@nestjs/graphql'; @ObjectType() export class Blob { diff --git a/servers/lib/test/e2e/app.e2e.spec.ts b/servers/lib/test/e2e/app.e2e.spec.ts index ce9c7c40e..75517c93f 100644 --- a/servers/lib/test/e2e/app.e2e.spec.ts +++ b/servers/lib/test/e2e/app.e2e.spec.ts @@ -1,16 +1,16 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { INestApplication } from "@nestjs/common"; -import * as request from "supertest"; +import { Test, TestingModule } from '@nestjs/testing'; +import { INestApplication } from '@nestjs/common'; +import * as request from 'supertest'; // import { execSync } from "child_process"; -import AppModule from "../../src/app.module"; +import AppModule from '../../src/app.module'; import { e2eReadFile, e2elistDirectory, expectedFileContentResponse, expectedListDirectoryResponse, -} from "../testUtil"; +} from '../testUtil'; -describe("End to End test for the application", () => { +describe('End to End test for the application', () => { let app: INestApplication; beforeAll(async () => { @@ -32,19 +32,19 @@ describe("End to End test for the application", () => { await app.close(); }, 10000); - it("should return the filename corresponding to the directory given in the query", async () => { + it('should return the filename corresponding to the directory given in the query', async () => { const query = e2elistDirectory; - const response = await request("http://localhost:4001") + const response = await request('http://localhost:4001') .post(process.env.APOLLO_PATH) .send({ query }); expect(response.body).toEqual(expectedListDirectoryResponse); }, 10000); - it("should return the content of a file given in the query ", async () => { + it('should return the content of a file given in the query ', async () => { const query = e2eReadFile; - const response = await request("http://localhost:4001") + const response = await request('http://localhost:4001') .post(process.env.APOLLO_PATH) .send({ query }); expect(response.body).toEqual(expectedFileContentResponse); diff --git a/servers/lib/test/integration/files.service.integration.spec.ts b/servers/lib/test/integration/files.service.integration.spec.ts index 780e529c1..d174eea19 100644 --- a/servers/lib/test/integration/files.service.integration.spec.ts +++ b/servers/lib/test/integration/files.service.integration.spec.ts @@ -1,18 +1,18 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { ConfigService } from "@nestjs/config"; -import FilesResolver from "../../src/files/resolvers/files.resolver"; -import FilesServiceFactory from "../../src/files/services/files-service.factory"; -import LocalFilesService from "../../src/files/services/local-files.service"; -import GitlabFilesService from "../../src/files/services/gitlab-files.service"; +import { Test, TestingModule } from '@nestjs/testing'; +import { ConfigService } from '@nestjs/config'; +import FilesResolver from '../../src/files/resolvers/files.resolver'; +import FilesServiceFactory from '../../src/files/services/files-service.factory'; +import LocalFilesService from '../../src/files/services/local-files.service'; +import GitlabFilesService from '../../src/files/services/gitlab-files.service'; import { pathToTestDirectory, pathToTestFileContent, testDirectory, testFileContent, MockConfigService, -} from "../testUtil"; +} from '../testUtil'; -describe("Integration tests for FilesResolver", () => { +describe('Integration tests for FilesResolver', () => { let filesResolver: FilesResolver; let mockConfigService: MockConfigService; @@ -35,29 +35,29 @@ describe("Integration tests for FilesResolver", () => { jest.clearAllMocks(); }); - const modes = ["local", "gitlab"]; + const modes = ['local', 'gitlab']; // eslint-disable-next-line no-restricted-syntax for (const mode of modes) { - // eslint-disable-next-line no-loop-func - describe(`when MODE is ${mode}`, () => { + // eslint-disable-next-line no-loop-func + describe(`when MODE is ${mode}`, () => { beforeEach(() => { - jest.spyOn(mockConfigService, "get").mockReturnValue(mode); + jest.spyOn(mockConfigService, 'get').mockReturnValue(mode); }); - it("should be defined", () => { + it('should be defined', () => { expect(filesResolver).toBeDefined(); }); - describe("listDirectory", () => { - it("should list files", async () => { + describe('listDirectory', () => { + it('should list files', async () => { const files = await filesResolver.listDirectory(pathToTestDirectory); expect(files).toEqual(testDirectory); }); }); - describe("readFile", () => { - it("should read file", async () => { + describe('readFile', () => { + it('should read file', async () => { const content = await filesResolver.readFile(pathToTestFileContent); expect(content).toEqual(testFileContent); }); diff --git a/servers/lib/test/testUtil.ts b/servers/lib/test/testUtil.ts index 2c9f2bb0f..4376f2aec 100644 --- a/servers/lib/test/testUtil.ts +++ b/servers/lib/test/testUtil.ts @@ -1,12 +1,12 @@ -import * as dotenv from "dotenv"; -import { setTimeout } from "timers/promises"; +import * as dotenv from 'dotenv'; +import { setTimeout } from 'timers/promises'; -dotenv.config({ path: ".env" }); +dotenv.config({ path: '.env' }); // actual data for integration and e2e tests -export const readFileActualContent = ["content123"]; +export const readFileActualContent = ['content123']; -export const pathToTestDirectory = "user2"; +export const pathToTestDirectory = 'user2'; export const testDirectory = { repository: { @@ -14,34 +14,34 @@ export const testDirectory = { blobs: { edges: [] }, trees: { edges: [ - { node: { name: "data", type: "tree" } }, - { node: { name: "digital_twins", type: "tree" } }, - { node: { name: "functions", type: "tree" } }, - { node: { name: "models", type: "tree" } }, - { node: { name: "tools", type: "tree" } }, + { node: { name: 'data', type: 'tree' } }, + { node: { name: 'digital_twins', type: 'tree' } }, + { node: { name: 'functions', type: 'tree' } }, + { node: { name: 'models', type: 'tree' } }, + { node: { name: 'tools', type: 'tree' } }, ], }, }, }, }; -export const testFileName = "README.md"; -export const fstestFileContent = "content123"; -export const pathToTestFileContent = "user2/tools/README.md"; +export const testFileName = 'README.md'; +export const fstestFileContent = 'content123'; +export const pathToTestFileContent = 'user2/tools/README.md'; export const testFileArray = [ - "data", - "digital_twins", - "functions", - "models", - "tools", + 'data', + 'digital_twins', + 'functions', + 'models', + 'tools', ]; export const testFileContent = { repository: { blobs: { nodes: [ { - name: "README.md", - rawBlob: "content123", - rawTextBlob: "content123", + name: 'README.md', + rawBlob: 'content123', + rawTextBlob: 'content123', }, ], }, @@ -57,22 +57,23 @@ export class MockConfigService { // eslint-disable-next-line class-methods-use-this get(key: string): string { switch (key) { - case "TOKEN": + case 'TOKEN': return process.env.TOKEN; - case "LOCAL_PATH": + case 'LOCAL_PATH': return process.env.TEST_PATH; - case "GITLAB_URL": + case 'GITLAB_URL': return process.env.GITLAB_URL; - case "GITLAB_GROUP": - return "dtaas"; - case "MODE": - if (process.env.MODE === "gitlab") { - return "gitlab"; - } if (process.env.MODE === "local") { - return "local"; - } - return "unknown"; - + case 'GITLAB_GROUP': + return 'dtaas'; + case 'MODE': + if (process.env.MODE === 'gitlab') { + return 'gitlab'; + } + if (process.env.MODE === 'local') { + return 'local'; + } + return 'unknown'; + default: return undefined; } @@ -81,16 +82,16 @@ export class MockConfigService { export const mockReadFileResponseData = { project: { - __typename: "Project", + __typename: 'Project', repository: { - __typename: "Repository", + __typename: 'Repository', blobs: { nodes: [ { - __typename: "Blob", - name: "README.md", - rawBlob: "content123", - rawTextBlob: "content123", + __typename: 'Blob', + name: 'README.md', + rawBlob: 'content123', + rawTextBlob: 'content123', }, ], }, @@ -107,27 +108,27 @@ export const expectedListDirectoryResponse = { edges: [ { node: { - name: "data", + name: 'data', }, }, { node: { - name: "digital_twins", + name: 'digital_twins', }, }, { node: { - name: "functions", + name: 'functions', }, }, { node: { - name: "models", + name: 'models', }, }, { node: { - name: "tools", + name: 'tools', }, }, ], @@ -145,9 +146,9 @@ export const expectedFileContentResponse = { blobs: { nodes: [ { - name: "README.md", - rawBlob: "content123", - rawTextBlob: "content123", + name: 'README.md', + rawBlob: 'content123', + rawTextBlob: 'content123', }, ], }, diff --git a/servers/lib/test/unit/files-service.factory.unit.spec.ts b/servers/lib/test/unit/files-service.factory.unit.spec.ts index a5751fdb7..7759f9818 100644 --- a/servers/lib/test/unit/files-service.factory.unit.spec.ts +++ b/servers/lib/test/unit/files-service.factory.unit.spec.ts @@ -1,12 +1,12 @@ // files-service.factory.spec.ts -import { Test, TestingModule } from "@nestjs/testing"; -import { ConfigService } from "@nestjs/config"; -import FilesServiceFactory from "../../src/files/services/files-service.factory"; -import LocalFilesService from "../../src/files/services/local-files.service"; -import GitlabFilesService from "../../src/files/services/gitlab-files.service"; -import { IFilesService } from "../../src/files/interfaces/files.service.interface"; +import { Test, TestingModule } from '@nestjs/testing'; +import { ConfigService } from '@nestjs/config'; +import FilesServiceFactory from '../../src/files/services/files-service.factory'; +import LocalFilesService from '../../src/files/services/local-files.service'; +import GitlabFilesService from '../../src/files/services/gitlab-files.service'; +import { IFilesService } from '../../src/files/interfaces/files.service.interface'; -describe("FilesServiceFactory", () => { +describe('FilesServiceFactory', () => { let serviceFactory: FilesServiceFactory; let configService: ConfigService; let localFilesService: IFilesService; @@ -29,18 +29,18 @@ describe("FilesServiceFactory", () => { configService = module.get(ConfigService); }); - it("should create a local files service when MODE is local", () => { - jest.spyOn(configService, "get").mockReturnValue("local"); + it('should create a local files service when MODE is local', () => { + jest.spyOn(configService, 'get').mockReturnValue('local'); expect(serviceFactory.create()).toBe(localFilesService); }); - it("should create a gitlab files service when MODE is gitlab", () => { - jest.spyOn(configService, "get").mockReturnValue("gitlab"); + it('should create a gitlab files service when MODE is gitlab', () => { + jest.spyOn(configService, 'get').mockReturnValue('gitlab'); expect(serviceFactory.create()).toBe(gitlabFilesService); }); - it("should throw an error when MODE is invalid", () => { - jest.spyOn(configService, "get").mockReturnValue("invalid"); + it('should throw an error when MODE is invalid', () => { + jest.spyOn(configService, 'get').mockReturnValue('invalid'); expect(() => serviceFactory.create()).toThrowError(`Invalid MODE: invalid`); }); }); diff --git a/servers/lib/test/unit/files.resolver.unit.spec.ts b/servers/lib/test/unit/files.resolver.unit.spec.ts index 62dcaab6d..850e50212 100644 --- a/servers/lib/test/unit/files.resolver.unit.spec.ts +++ b/servers/lib/test/unit/files.resolver.unit.spec.ts @@ -1,15 +1,15 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import FilesResolver from "../../src/files/resolvers/files.resolver"; +import { Test, TestingModule } from '@nestjs/testing'; +import FilesResolver from '../../src/files/resolvers/files.resolver'; import { testDirectory, pathToTestDirectory, pathToTestFileContent, testFileContent, -} from "../testUtil"; -import { IFilesService } from "../../src/files/interfaces/files.service.interface"; -import FilesServiceFactory from "../../src/files/services/files-service.factory"; +} from '../testUtil'; +import { IFilesService } from '../../src/files/interfaces/files.service.interface'; +import FilesServiceFactory from '../../src/files/services/files-service.factory'; -describe("Unit tests for FilesResolver", () => { +describe('Unit tests for FilesResolver', () => { let filesResolver: FilesResolver; let filesService: IFilesService; @@ -38,30 +38,30 @@ describe("Unit tests for FilesResolver", () => { .create(); }); - it("should be defined", () => { + it('should be defined', () => { expect(filesResolver).toBeDefined(); }); - describe("listDirectory", () => { - it("should be defined", () => { + describe('listDirectory', () => { + it('should be defined', () => { expect(filesResolver.listDirectory).toBeDefined(); }); - it("should list files in directory", async () => { + it('should list files in directory', async () => { const result = await filesResolver.listDirectory(pathToTestDirectory); expect(result).toEqual(testDirectory); expect(filesService.listDirectory).toHaveBeenCalledWith( - pathToTestDirectory + pathToTestDirectory, ); }); }); - describe("readFile", () => { - it("should be defined", () => { + describe('readFile', () => { + it('should be defined', () => { expect(filesResolver.readFile).toBeDefined(); }); - it("should read file", async () => { + it('should read file', async () => { const result = await filesResolver.readFile(pathToTestFileContent); expect(result).toEqual(testFileContent); expect(filesService.readFile).toHaveBeenCalledWith(pathToTestFileContent); diff --git a/servers/lib/test/unit/gitlab-files.service.unit.spec.ts b/servers/lib/test/unit/gitlab-files.service.unit.spec.ts index 46b237ba1..f26a9712a 100644 --- a/servers/lib/test/unit/gitlab-files.service.unit.spec.ts +++ b/servers/lib/test/unit/gitlab-files.service.unit.spec.ts @@ -1,13 +1,18 @@ -import { Test, TestingModule } from "@nestjs/testing"; -import { ConfigService } from "@nestjs/config"; -import axios from "axios"; -import GitlabFilesService from "../../src/files/services/gitlab-files.service"; -import { pathToTestFileContent, testFileContent , MockConfigService, testDirectory } from "../testUtil"; +import { Test, TestingModule } from '@nestjs/testing'; +import { ConfigService } from '@nestjs/config'; +import axios from 'axios'; +import GitlabFilesService from '../../src/files/services/gitlab-files.service'; +import { + pathToTestFileContent, + testFileContent, + MockConfigService, + testDirectory, +} from '../testUtil'; -describe("GitlabFilesService", () => { +describe('GitlabFilesService', () => { let filesService: GitlabFilesService; const mockConfigService = new MockConfigService(); - jest.mock("axios"); + jest.mock('axios'); beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ @@ -23,16 +28,16 @@ describe("GitlabFilesService", () => { filesService = module.get(GitlabFilesService); }); - it("should list directory", async () => { - jest.spyOn(axios, "post").mockResolvedValue({ data: testDirectory }); + it('should list directory', async () => { + jest.spyOn(axios, 'post').mockResolvedValue({ data: testDirectory }); - const result = await filesService.listDirectory("user2"); + const result = await filesService.listDirectory('user2'); expect(result).toEqual(testDirectory); }); - it("should read file", async () => { + it('should read file', async () => { jest - .spyOn(axios, "post") + .spyOn(axios, 'post') .mockResolvedValue({ data: { data: testFileContent } }); const result = await filesService.readFile(pathToTestFileContent); diff --git a/servers/lib/test/unit/local-files.service.unit.spec.ts b/servers/lib/test/unit/local-files.service.unit.spec.ts index 3c5f175b1..72e4835be 100644 --- a/servers/lib/test/unit/local-files.service.unit.spec.ts +++ b/servers/lib/test/unit/local-files.service.unit.spec.ts @@ -46,7 +46,7 @@ describe('LocalFilesService', () => { it('should list directory', async () => { const fullPath = join( mockConfigService.get('LOCAL_PATH'), - pathToTestDirectory + pathToTestDirectory, ); // Mock Stats value for lstat @@ -58,14 +58,12 @@ describe('LocalFilesService', () => { .spyOn(fs.promises, 'readdir') .mockResolvedValue(testFileArray as unknown as Promise<[]>); - jest - .spyOn(fs.promises, 'lstat') - .mockImplementation((pathToDirectory) => { - if (typeof pathToDirectory === 'string') { - return Promise.resolve(statsMock as fs.Stats); - } - throw new Error(`Invalid argument: ${pathToDirectory}`); - }); + jest.spyOn(fs.promises, 'lstat').mockImplementation((pathToDirectory) => { + if (typeof pathToDirectory === 'string') { + return Promise.resolve(statsMock as fs.Stats); + } + throw new Error(`Invalid argument: ${pathToDirectory}`); + }); const result = await service.listDirectory(pathToTestDirectory); expect(result).toEqual({ repository: { @@ -86,7 +84,7 @@ describe('LocalFilesService', () => { it('should read file', async () => { const fullPath = join( mockConfigService.get('LOCAL_PATH'), - pathToTestFileContent + pathToTestFileContent, ); jest.spyOn(fs.promises, 'readFile').mockResolvedValue(fstestFileContent);