diff --git a/.github/workflows/nest.js.yml b/.github/workflows/nest.js.yml new file mode 100644 index 000000000..95a824874 --- /dev/null +++ b/.github/workflows/nest.js.yml @@ -0,0 +1,116 @@ +# SPDX-FileCopyrightText: 2020 The HedgeDoc developers (see AUTHORS file) +# +# SPDX-License-Identifier: AGPL-3.0-only + + +name: Nest.JS CI + +on: + push: + branches: [ develop ] + pull_request: + branches: [ develop ] + +jobs: + lint: + runs-on: ubuntu-latest + strategy: + matrix: + command: + - yarn run lint + - yarn run format:check + steps: + - uses: actions/checkout@v2 + - name: Use Node.js 14 + uses: actions/setup-node@v1 + with: + node-version: 14 + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + - uses: actions/cache@v2 + id: yarn-cache + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + - run: yarn --frozen-lockfile --prefer-offline + - run: ${{matrix.command}} + build: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [ 10.x, 12.x, 14.x, 15.x ] + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + - uses: actions/cache@v2 + id: yarn-cache + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + - run: yarn --frozen-lockfile --prefer-offline + - run: yarn run build + + integration-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Use Node.js 14 + uses: actions/setup-node@v1 + with: + node-version: 14 + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + - uses: actions/cache@v2 + id: yarn-cache + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + - run: yarn --frozen-lockfile --prefer-offline + - run: yarn run test:cov + - uses: codecov/codecov-action@v1 + with: + directory: coverage + flags: integration-tests + + e2e-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Use Node.js 14 + uses: actions/setup-node@v1 + with: + node-version: 14 + - name: Get yarn cache directory path + id: yarn-cache-dir-path + run: echo "::set-output name=dir::$(yarn cache dir)" + - uses: actions/cache@v2 + id: yarn-cache + with: + path: ${{ steps.yarn-cache-dir-path.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn- + - run: yarn --frozen-lockfile --prefer-offline + - run: yarn run test:e2e:cov + - uses: codecov/codecov-action@v1 + with: + directory: coverage-e2e + flags: e2e-tests diff --git a/.gitignore b/.gitignore index 8ed1dd535..608b69597 100644 --- a/.gitignore +++ b/.gitignore @@ -35,7 +35,9 @@ dist # Tests /coverage +/coverage-e2e /.nyc_output public/uploads/* !public/uploads/.gitkeep +uploads diff --git a/README.md b/README.md index b8aa8f652..93d5f2a6a 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,9 @@ HedgeDoc 2 [![version][github-version-badge]][github-release-page] [![POEditor][poeditor-image]][poeditor-url] [![Mastodon][social-mastodon-image]][social-mastodon] +![REUSE Compliance Check][reuse-workflow-badge] +![Nest.JS CI][nestjs-workflow-badge] +[![codecov][codecov-badge]][codecov-url] HedgeDoc lets you create real-time collaborative markdown notes. Have a look at [our website](https://hedgedoc.org) for more details. @@ -60,9 +63,23 @@ the [github repository](https://github.com/hedgedoc/hedgedoc-logo). [poeditor-image]: https://img.shields.io/badge/POEditor-translate-blue.svg [poeditor-url]: https://poeditor.com/join/project/1OpGjF2Jir + [hedgedoc-demo]: https://demo.hedgedoc.org + [hedgedoc-demo-features]: https://demo.hedgedoc.org/features + [hedgedoc-community]: https://community.hedgedoc.org + [hedgedoc-community-calls]: https://community.hedgedoc.org/t/codimd-community-call/19 + [social-mastodon]: https://social.hedgedoc.org/mastodon + [social-mastodon-image]: https://img.shields.io/mastodon/follow/49593?domain=https%3A%2F%2Fsocial.snopyta.org&style=social + +[reuse-workflow-badge]: https://github.com/hedgedoc/hedgedoc/workflows/REUSE%20Compliance%20Check/badge.svg + +[nestjs-workflow-badge]: https://github.com/hedgedoc/hedgedoc/workflows/Nest.JS%20CI/badge.svg + +[codecov-badge]: https://codecov.io/gh/hedgedoc/hedgedoc/branch/develop/graph/badge.svg?token=pdaRF4qjNQ + +[codecov-url]: https://codecov.io/gh/hedgedoc/hedgedoc diff --git a/package.json b/package.json index e21f55c4b..492b01f36 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "prebuild": "rimraf dist", "build": "nest build", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", + "format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"", "start": "nest start", "start:dev": "nest start --watch", "start:debug": "nest start --debug --watch", @@ -19,7 +20,8 @@ "test:watch": "jest --watch", "test:cov": "jest --coverage", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", - "test:e2e": "jest --config jest-e2e.json" + "test:e2e": "jest --config jest-e2e.json", + "test:e2e:cov": "jest --config jest-e2e.json --coverage" }, "dependencies": { "@nestjs/common": "7.4.4", diff --git a/src/api/utils/markdownbody-decorator.ts b/src/api/utils/markdownbody-decorator.ts index 9ab99b948..289367ffd 100644 --- a/src/api/utils/markdownbody-decorator.ts +++ b/src/api/utils/markdownbody-decorator.ts @@ -17,21 +17,24 @@ import * as getRawBody from 'raw-body'; * * Implementation inspired by https://stackoverflow.com/questions/52283713/how-do-i-pass-plain-text-as-my-request-body-using-nestjs */ -export const MarkdownBody = createParamDecorator(async (_, context: ExecutionContext) => { - // we have to check req.readable because of raw-body issue #57 - // https://github.com/stream-utils/raw-body/issues/57 - const req = context.switchToHttp().getRequest(); - // Here the Content-Type of the http request is checked to be text/markdown - // because we dealing with markdown. Technically by now there can be any content which can be encoded. - // There could be features in the software which do not work properly if the text can't be parsed as markdown. - if (req.get('Content-Type') === 'text/markdown') { - if (req.readable) { - return (await getRawBody(req)).toString().trim(); +export const MarkdownBody = createParamDecorator( + async (_, context: ExecutionContext) => { + // we have to check req.readable because of raw-body issue #57 + // https://github.com/stream-utils/raw-body/issues/57 + const req = context.switchToHttp().getRequest(); + // Here the Content-Type of the http request is checked to be text/markdown + // because we dealing with markdown. Technically by now there can be any content which can be encoded. + // There could be features in the software which do not work properly if the text can't be parsed as markdown. + if (req.get('Content-Type') === 'text/markdown') { + if (req.readable) { + return (await getRawBody(req)).toString().trim(); + } else { + throw new InternalServerErrorException('Failed to parse request body!'); + } } else { - throw new InternalServerErrorException('Failed to parse request body!'); + throw new BadRequestException( + 'Body Content-Type has to be text/markdown!', + ); } - } else { - throw new BadRequestException('Body Content-Type has to be text/markdown!'); - } - -}); + }, +); diff --git a/src/monitoring/monitoring.service.ts b/src/monitoring/monitoring.service.ts index 97b6ede1c..597e8bb79 100644 --- a/src/monitoring/monitoring.service.ts +++ b/src/monitoring/monitoring.service.ts @@ -25,7 +25,7 @@ async function getServerVersionFromPackageJson() { const packageInfo: { version: string } = JSON.parse(rawFileContent); const versionParts: number[] = packageInfo.version .split('.') - .map((x) => parseInt(x, 10)); + .map(x => parseInt(x, 10)); versionCache = { major: versionParts[0], minor: versionParts[1], diff --git a/src/revisions/authorship.entity.ts b/src/revisions/authorship.entity.ts index 1bd8d1591..9ac5aa874 100644 --- a/src/revisions/authorship.entity.ts +++ b/src/revisions/authorship.entity.ts @@ -5,11 +5,13 @@ */ import { - Column, CreateDateColumn, + Column, + CreateDateColumn, Entity, ManyToMany, ManyToOne, - PrimaryGeneratedColumn, UpdateDateColumn, + PrimaryGeneratedColumn, + UpdateDateColumn, } from 'typeorm/index'; import { User } from '../users/user.entity'; import { Revision } from './revision.entity'; @@ -38,14 +40,14 @@ export class Authorship { user: User; @Column() - startPos: number + startPos: number; @Column() - endPos: number + endPos: number; @CreateDateColumn() - createdAt: Date + createdAt: Date; @UpdateDateColumn() - updatedAt: Date + updatedAt: Date; } diff --git a/test/public-api/users.e2e-spec.ts b/test/public-api/users.e2e-spec.ts index 9c5f2e18d..495f58e12 100644 --- a/test/public-api/users.e2e-spec.ts +++ b/test/public-api/users.e2e-spec.ts @@ -124,7 +124,6 @@ describe('Notes', () => { expect(historyEntry.pinStatus).toEqual(true); }); - it.skip(`GET /me/notes/`, async () => { // TODO use function from HistoryService to add an History Entry await notesService.createNote('This is a test note.', 'test7');