Skip to content

Commit

Permalink
Merge branch 'master' into filter-by-event-type-list
Browse files Browse the repository at this point in the history
  • Loading branch information
johannaengland committed Feb 9, 2024
2 parents 98b33e7 + d0a8354 commit b56e5aa
Show file tree
Hide file tree
Showing 14 changed files with 161 additions and 6 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/towncrier.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Check for changelog file

on: [pull_request]

jobs:
towncrier:
runs-on: ubuntu-latest
name: Towncrier check
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Install towncrier
run: |
pip install -U pip
pip install towncrier
- name: Check for changelog file
run: towncrier check --compare-with origin/master
7 changes: 7 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ repos:
- id: trailing-whitespace
- id: mixed-line-ending
- id: end-of-file-fixer
exclude: &exclude_pattern '^changelog.d/'
- id: debug-statements
- repo: https://github.com/pycqa/flake8
rev: 3.9.2
Expand All @@ -17,3 +18,9 @@ repos:
hooks:
- id: black
exclude: migrations/
- repo: https://github.com/twisted/towncrier
rev: 23.11.0
hooks:
- id: towncrier-check
files: $changelog\.d/
args: [--compare-with origin/master]
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@
This file documents all changes to Argus. This file is primarily meant to be
read by developers.

## [Unreleased]
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

This project uses [*towncrier*](https://towncrier.readthedocs.io/) and the changes for the upcoming release can be found in <https://github.com/Uninett/Argus/tree/master/changelog.d/>.

<!-- towncrier release notes start -->

### Added
- Added the possibility to filter incident by a given list of ids
- Add the "admin_url" field to the user serializer. This is so that the
frontend can show a link to the Django admin.

## [1.14.1 - 2023-12-05]

Expand Down
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,42 @@ $ tox
```
An [HTML coverage report](htmlcov/index.html) will be generated.
Refer to the [tox.ini](tox.ini) file for further options.

## Using towncrier to automatically produce the changelog
### Before opening a PR
To be able to automatically produce the changelog for a release a file for each
pull request (also called news fragment) needs to be added to the folder
`changelog.d/`.
The name of the file consists of three parts seperated by a period:
1. The identifier, either the issue number this pull request is refering to or if
there is no related issue a `+` followed by a unique short description.
2. The type of the change, we use `critical`, `added`, `changed` and `fixed`.
3. The file suffix, e.g. `.md`, towncrier does not care which suffix a fragment has.

So an example for a file name linked to an issue would be `214.added.md` or for a file
without corresponding issue `+fixed-pagination-bug.fixed.md`.

This file can either be created manually with a file name as specified above and the
changelog text as content or one can use towncrier to create such a file as following:

```console
$ towncrier create -c "Changelog content" 214.added.md
```

When opening a PR there will be a check to make sure that a news fragment is added, it
will fail if it is missing.

### Before a release
To add all content from the `changelog.d/` folder to the changelog file simply run
```console
$ towncrier build --version {version}
```
This will also delete all files in `changelog.d/`.

To preview what the addition to the changelog file would look like add the flag `--draft`.

A few other helpful flags:
- `date DATE` - set the date of the release, default is today
- `keep` - keep all news fragments

More information about [towncrier](https://towncrier.readthedocs.io).
1 change: 1 addition & 0 deletions changelog.d/+towncrier-changelog.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added towncrier to automatically produce changelog
16 changes: 16 additions & 0 deletions changelog.d/+two-optional-dependencies.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Add two development dependencies

While `tox` doesn't need to be in the venv, it DOES currently need to be less
than version 4.

`build` is useful for debugging pip errors and pip-compile trouble.
Whenever pip-compile (via `tox -e upgrade-deps` for instance) fails with

```
Backend subprocess exited when trying to invoke get_requires_for_build_wheel
Failed to parse /PATH/pyproject.toml
```

run `python -m build -w` to see what `build` is actually complaining about.

See also https://github.com/pypa/build/issues/553
Empty file added changelog.d/.gitkeep
Empty file.
32 changes: 32 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ dev = [
"ipython",
"pre-commit",
"python-dotenv",
"towncrier",
"werkzeug",
"tox<4", # does not work on tox 4 for some reason
"build", # for debugging builds/installs
]

[tool.setuptools]
Expand Down Expand Up @@ -104,3 +107,32 @@ exclude = '''
| src/.*/migrations
)
'''

[tool.towncrier]
directory = "changelog.d"
filename = "CHANGELOG.md"
start_string = "<!-- towncrier release notes start -->\n"
underlines = ["", "", ""]
title_format = "## [{version}] - {project_date}"
issue_format = "[#{issue}](https://github.com/Uninett/Argus/issues/{issue})"
wrap = true

[[tool.towncrier.type]]
directory = "critical"
name = "Critical"
showcontent = true

[[tool.towncrier.type]]
directory = "added"
name = "Added"
showcontent = true

[[tool.towncrier.type]]
directory = "changed"
name = "Changed"
showcontent = true

[[tool.towncrier.type]]
directory = "fixed"
name = "Fixed"
showcontent = true
15 changes: 13 additions & 2 deletions src/argus/auth/serializers.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
from rest_framework import exceptions, serializers
from rest_framework.authtoken.models import Token
from typing import Optional

from rest_framework import serializers
from rest_framework.reverse import reverse


from .models import User


class UserSerializer(serializers.ModelSerializer):
admin_url = serializers.SerializerMethodField(method_name="get_admin_url")

class Meta:
model = User
fields = [
"username",
"first_name",
"last_name",
"email",
"admin_url",
]

def get_admin_url(self, user: User) -> Optional[str]:
if self.context.get("request") and user.is_staff:
return reverse("admin:index", request=self.context["request"])
return None


class BasicUserSerializer(serializers.ModelSerializer):
class Meta:
Expand Down
2 changes: 1 addition & 1 deletion src/argus/auth/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class CurrentUserView(APIView):
serializer_class = UserSerializer

def get(self, request, *args, **kwargs):
serializer = self.serializer_class(request.user)
serializer = self.serializer_class(instance=request.user, context={"request": request})
return Response(serializer.data)


Expand Down
4 changes: 4 additions & 0 deletions src/argus/incident/V1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
description="Fetch incidents that ended on or before `END_TIME`",
type=OpenApiTypes.DATETIME,
),
OpenApiParameter(
name="id__in",
description="Fetch the incidents with an id in the given id list.",
),
OpenApiParameter(
name="level__lte",
description="Fetch incidents with levels less than or equal to `LEVEL`",
Expand Down
1 change: 1 addition & 0 deletions src/argus/incident/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def incident_filter(cls, queryset, name, value):
class Meta:
model = Incident
fields = {
"id": ["in"],
"source__id": ["in"],
"source__name": ["in"],
"source__type": ["in"],
Expand Down
4 changes: 4 additions & 0 deletions src/argus/incident/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ def _set_available_username(form: AddSourceSystemForm):
description="Fetch incidents that ended on or before `END_TIME`",
type=OpenApiTypes.DATETIME,
),
OpenApiParameter(
name="id__in",
description="Fetch the incidents with an id in the given id list.",
),
OpenApiParameter(
name="level__lte", description="Fetch incidents with levels in `LEVEL`", enum=Incident.LEVELS
),
Expand Down
16 changes: 14 additions & 2 deletions tests/auth/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,31 @@ class ViewTests(APITestCase):
def setUp(self):
disconnect_signals()
self.user1 = AdminUserFactory(username="user1")
self.user2 = BaseUserFactory(username="user2")

self.user1_rest_client = APIClient()
self.user1_rest_client.force_authenticate(user=self.user1)
self.user2_rest_client = APIClient()
self.user2_rest_client.force_authenticate(user=self.user2)

def teardown(self):
connect_signals()

def test_can_get_specific_user(self):
user2_pk = BaseUserFactory(username="user2").pk
response = self.user1_rest_client.get(path=f"/api/v2/auth/users/{user2_pk}/")
response = self.user1_rest_client.get(path=f"/api/v2/auth/users/{self.user2.pk}/")
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["username"], "user2")

def test_can_get_admin_url_if_user_is_staff(self):
response = self.user1_rest_client.get(path="/api/v2/auth/user/")
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIn("admin", response.data["admin_url"])

def test_cannot_get_admin_url_if_user_is_not_staff(self):
response = self.user2_rest_client.get(path="/api/v2/auth/user/")
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertFalse(response.data["admin_url"])

def test_can_get_current_user(self):
response = self.user1_rest_client.get(path="/api/v2/auth/user/")
self.assertEqual(response.status_code, status.HTTP_200_OK)
Expand Down

0 comments on commit b56e5aa

Please sign in to comment.