Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ def env(name, default=NoDefaultValue, type_=str):
"TaskStatusEnum": "metecho.api.models.TaskStatus.choices",
"EpicStatusEnum": "metecho.api.models.EpicStatus.choices",
"ReviewStatusEnum": "metecho.api.models.TaskReviewStatus.choices",
"TaskActivityTypeEnum": "metecho.api.models.TaskActivityType.choices",
},
"SERVE_INCLUDE_SCHEMA": False, # Don't include schema view in docs
}
Expand Down
114 changes: 114 additions & 0 deletions docs/api/schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,54 @@ paths:
schema:
$ref: '#/components/schemas/ScratchOrg'
description: ''
/api/task-activities/:
get:
operationId: task_activities_list
description: Activity log related to project Tasks.
parameters:
- in: query
name: task
schema:
type: string
format: HashID
tags:
- task-activities
security:
- tokenAuth: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/TaskActivity'
description: ''
/api/task-activities/{id}/:
get:
operationId: task_activities_retrieve
description: Activity log related to project Tasks.
parameters:
- in: path
name: id
schema:
type: string
format: HashID
description: A unique integer value identifying this task activity.
required: true
tags:
- task-activities
security:
- tokenAuth: []
- cookieAuth: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/TaskActivity'
description: ''
/api/tasks/:
get:
operationId: tasks_list
Expand Down Expand Up @@ -2399,6 +2447,72 @@ components:
- root_project
- slug
- status
TaskActivity:
type: object
properties:
id:
type: string
readOnly: true
created_at:
type: string
format: date-time
readOnly: true
type:
allOf:
- $ref: '#/components/schemas/TaskActivityTypeEnum'
readOnly: true
link_title:
type: string
readOnly: true
link_url:
type: string
format: uri
readOnly: true
description:
type: string
readOnly: true
task:
type: string
format: HashID
readOnly: true
collaborator_id:
type: string
readOnly: true
scratch_org:
type: string
format: HashID
readOnly: true
nullable: true
required:
- collaborator_id
- created_at
- description
- id
- link_title
- link_url
- scratch_org
- task
- type
TaskActivityTypeEnum:
enum:
- Merged
- Approved
- Closed
- Test Org created
- Test Org deleted
- Dev Org created
- Dev Org deleted
- Submitted for testing
- Changes retrieved
- Changes requested
- Tester accepted
- Tester assigned
- Tester unassigned
- Developer accepted
- Developer assigned
- Developer unassigned
- Created
type: string
TaskAssignee:
type: object
properties:
Expand Down
10 changes: 10 additions & 0 deletions metecho/api/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
ScratchOrg,
SiteProfile,
Task,
TaskActivity,
TaskSlug,
User,
)
Expand Down Expand Up @@ -182,6 +183,15 @@ class TaskSlugAdmin(admin.ModelAdmin):
search_fields = ("slug",)


@admin.register(TaskActivity)
class TaskActivityAdmin(admin.ModelAdmin):
list_display = ("type", "description", "task", "created_at")
list_filter = ("type",)
list_select_related = ("task",)
date_hierarchy = "created_at"
autocomplete_fields = ("task", "scratch_org")


@admin.register(ScratchOrg)
class ScratchOrgAdmin(admin.ModelAdmin):
list_display = (
Expand Down
8 changes: 7 additions & 1 deletion metecho/api/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from django.utils.translation import gettext_lazy as _
from django_filters import rest_framework as filters

from .models import Epic, GitHubIssue, Project, ScratchOrg, Task
from .models import Epic, GitHubIssue, Project, ScratchOrg, Task, TaskActivity


def slug_is_active(queryset, name, value):
Expand Down Expand Up @@ -66,6 +66,12 @@ def filter_project(self, queryset, name, project):
return queryset.filter(Q(project=project) | Q(epic__project=project))


class TaskActivityFilter(filters.FilterSet):
class Meta:
model = TaskActivity
fields = ("task",)


class ScratchOrgFilter(filters.FilterSet):
class Meta:
model = ScratchOrg
Expand Down
15 changes: 11 additions & 4 deletions metecho/api/hook_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,18 @@ class PrBranchSerializer(serializers.Serializer):
# All other fields are ignored by default.


class UserSerializer(serializers.Serializer):
id = serializers.IntegerField()
login = serializers.CharField()


class PrSerializer(serializers.Serializer):
merged = serializers.BooleanField(required=False)
head = PrBranchSerializer()
base = PrBranchSerializer()
number = serializers.IntegerField()
title = serializers.CharField()
user = UserSerializer()
# All other fields are ignored by default.


Expand Down Expand Up @@ -100,13 +107,13 @@ def process_hook(self):
# In all these, our originating user is None, because this
# comes from the GitHub hook, and therefore all users on the
# frontend should pay attention to it.
pr_number = self.validated_data["number"]
pr = self.validated_data["pull_request"]
if self._is_opened():
instance.finalize_pr_opened(pr_number, originating_user_id=None)
instance.finalize_pr_opened(pr, originating_user_id=None)
elif self._is_merged():
instance.finalize_status_completed(pr_number, originating_user_id=None)
instance.finalize_status_completed(pr, originating_user_id=None)
else:
instance.finalize_pr_closed(pr_number, originating_user_id=None)
instance.finalize_pr_closed(pr, originating_user_id=None)
Comment on lines +110 to +116
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now pass a full pr object to the finalize_* methods to have access to both the title and number (and other things if we ever need them in the future).



class CommitSerializer(serializers.Serializer):
Expand Down
10 changes: 9 additions & 1 deletion metecho/api/jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
normalize_commit,
try_to_make_branch,
)
from .models import TaskReviewStatus
from .models import TaskActivityType, TaskReviewStatus
from .push import report_scratch_org_error
from .sf_org_changes import (
commit_changes_to_github,
Expand Down Expand Up @@ -458,6 +458,14 @@ def commit_changes_from_org(
scratch_org.task.add_metecho_git_sha(commit.sha)
scratch_org.task.has_unmerged_commits = True
scratch_org.task.finalize_task_update(originating_user_id=originating_user_id)
scratch_org.task.log_activity(
type=TaskActivityType.CHANGES_RETRIEVED,
user_id=originating_user_id,
link_url=f"{scratch_org.task.root_project.repo_url}/commit/{commit.sha}",
link_title=commit.sha[:7],
description=commit_message,
scratch_org=scratch_org,
)

scratch_org.refresh_from_db()
scratch_org.last_modified_at = now()
Expand Down
93 changes: 93 additions & 0 deletions metecho/api/migrations/0109_taskactivity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Generated by Django 4.0 on 2021-12-10 21:39

import django.db.models.deletion
import hashid_field.field
import sfdo_template_helpers.fields.string
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("api", "0108_project_has_truncated_issues"),
]

operations = [
migrations.CreateModel(
name="TaskActivity",
fields=[
(
"id",
hashid_field.field.HashidAutoField(
alphabet="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", # noqa
min_length=7,
prefix="",
primary_key=True,
serialize=False,
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("edited_at", models.DateTimeField(auto_now=True)),
(
"type",
sfdo_template_helpers.fields.string.StringField(
choices=[
("Merged", "Merged"),
("Approved", "Approved"),
("Closed", "Closed"),
("Test Org created", "Test Org Created"),
("Test Org deleted", "Test Org Deleted"),
("Dev Org created", "Dev Org Created"),
("Dev Org deleted", "Dev Org Deleted"),
("Submitted for testing", "Submitted For Testing"),
("Changes retrieved", "Changes Retrieved"),
("Changes requested", "Changes Requested"),
("Tester accepted", "Tester Accepted"),
("Tester assigned", "Tester Assigned"),
("Tester unassigned", "Tester Unassigned"),
("Developer accepted", "Dev Accepted"),
("Developer assigned", "Dev Assigned"),
("Developer unassigned", "Dev Unassigned"),
("Created", "Created"),
]
),
),
(
"link_title",
sfdo_template_helpers.fields.string.StringField(blank=True),
),
("link_url", models.URLField(blank=True)),
(
"description",
sfdo_template_helpers.fields.string.StringField(blank=True),
),
(
"collaborator_id",
sfdo_template_helpers.fields.string.StringField(blank=True),
),
(
"scratch_org",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="task_activities",
to="api.scratchorg",
),
),
(
"task",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="activities",
to="api.task",
),
),
],
options={
"verbose_name": "task activity",
"verbose_name_plural": "task activities",
"ordering": ("-created_at",),
},
),
]
Loading