diff --git a/.coveragerc b/.coveragerc index c8f78b2..8c01599 100644 --- a/.coveragerc +++ b/.coveragerc @@ -2,4 +2,4 @@ concurrency = multiprocessing parallel = True relative_files = True -source = tremolo +source = tremolo/ diff --git a/.github/workflows/tests-and-coverage.yml b/.github/workflows/tests-and-coverage.yml index 6ab35f6..24c498f 100644 --- a/.github/workflows/tests-and-coverage.yml +++ b/.github/workflows/tests-and-coverage.yml @@ -59,7 +59,7 @@ jobs: path: artifact if: ${{ matrix.python-version == '3.12' }} report: - name: Upload Coverage to Codecov + name: Upload Coverage to Codecov & SonarCloud Scan needs: ['tests'] runs-on: ubuntu-latest steps: @@ -75,4 +75,9 @@ jobs: run: | python -m coverage combine artifact python -m coverage report --show-missing --skip-covered + python -m coverage xml - uses: codecov/codecov-action@v3 + - uses: sonarsource/sonarcloud-github-action@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # needed to get PR information, if any + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/README.md b/README.md index ee87b7a..16fc5f0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Tremolo [![codecov](https://codecov.io/gh/nggit/tremolo/branch/master/graph/badge.svg?token=SC8NVWN0F1)](https://codecov.io/gh/nggit/tremolo) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=nggit_tremolo&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=nggit_tremolo) Tremolo is a [stream-oriented](https://nggit.github.io/tremolo-docs/yield.html), asynchronous, programmable HTTP server written in pure Python. It can also serve as an [ASGI server](#asgi-server). @@ -36,7 +37,7 @@ And other use cases… ## Features Tremolo is only suitable for those who value [minimalism](https://en.wikipedia.org/wiki/Minimalism_%28computing%29) and stability over features. -With only 2500 lines of code, with no dependencies other than the [Python Standard Library](https://docs.python.org/3/library/index.html), it gives you: +With only 3K lines of code, with no dependencies other than the [Python Standard Library](https://docs.python.org/3/library/index.html), it gives you: * HTTP/1.x with [WebSocket support](https://nggit.github.io/tremolo-docs/websocket.html) * Keep-Alive connections with [configurable limit](https://nggit.github.io/tremolo-docs/configuration.html#keepalive_connections) diff --git a/setup.py b/setup.py index 8dca755..bf40cb0 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ setup( name='tremolo', - version='0.0.307', + version='0.0.308', license='MIT', author='nggit', author_email='contact@anggit.com', diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..398ac68 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,4 @@ +sonar.projectKey=nggit_tremolo +sonar.organization=nggit +sonar.sources=tremolo/ +sonar.python.coverage.reportPaths=coverage.xml diff --git a/tremolo/__init__.py b/tremolo/__init__.py index 5e74b9c..c5b9dbc 100644 --- a/tremolo/__init__.py +++ b/tremolo/__init__.py @@ -1,4 +1,4 @@ -__version__ = '0.0.307' +__version__ = '0.0.308' from .tremolo import Tremolo # noqa: E402 from . import exceptions # noqa: E402,F401 diff --git a/tremolo/lib/http_request.py b/tremolo/lib/http_request.py index 2e834e4..5a967db 100644 --- a/tremolo/lib/http_request.py +++ b/tremolo/lib/http_request.py @@ -258,8 +258,7 @@ def query(self): if self.query_string != b'': self.params['query'] = parse_qs( - self.query_string.decode('latin-1'), - max_num_fields=100 + self.query_string.decode('latin-1'), max_num_fields=100 ) return self.params['query'] @@ -345,7 +344,9 @@ async def files(self, limit=1024): except StopAsyncIteration: if header_size == -1 or body_size == -1: del body[:] - raise BadRequest('malformed multipart/form-data') + raise BadRequest( + 'malformed multipart/form-data: incomplete read' + ) if header is None: self._read_buf.extend(data) @@ -353,7 +354,9 @@ async def files(self, limit=1024): if header_size == -1: if len(self._read_buf) > 8192: - raise BadRequest('malformed multipart/form-data') + raise BadRequest( + 'malformed multipart/form-data: header too large' + ) paused = False else: