Skip to content

Commit 9530f35

Browse files
authored
feat(GitLab): Add GitLab to Project Integrations (#7239)
1 parent 742a554 commit 9530f35

File tree

13 files changed

+375
-1
lines changed

13 files changed

+375
-1
lines changed

api/app/settings/common.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@
154154
"integrations.flagsmith",
155155
"integrations.launch_darkly",
156156
"integrations.github",
157+
"integrations.gitlab",
157158
"integrations.grafana",
158159
# Rate limiting admin endpoints
159160
"axes",

api/integrations/gitlab/__init__.py

Whitespace-only changes.

api/integrations/gitlab/apps.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from django.apps import AppConfig
2+
3+
4+
class GitLabIntegrationConfig(AppConfig):
5+
name = "integrations.gitlab"
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Generated by Django 5.2.13
2+
3+
import uuid
4+
5+
import django.db.models.deletion
6+
from django.db import migrations, models
7+
8+
9+
class Migration(migrations.Migration):
10+
11+
initial = True
12+
13+
dependencies = [
14+
("projects", "0028_add_enforce_feature_owners_to_project"),
15+
]
16+
17+
operations = [
18+
migrations.CreateModel(
19+
name="GitLabConfiguration",
20+
fields=[
21+
(
22+
"id",
23+
models.AutoField(
24+
auto_created=True,
25+
primary_key=True,
26+
serialize=False,
27+
verbose_name="ID",
28+
),
29+
),
30+
(
31+
"deleted_at",
32+
models.DateTimeField(
33+
blank=True,
34+
db_index=True,
35+
default=None,
36+
editable=False,
37+
null=True,
38+
),
39+
),
40+
(
41+
"uuid",
42+
models.UUIDField(
43+
default=uuid.uuid4,
44+
editable=False,
45+
unique=True,
46+
),
47+
),
48+
(
49+
"gitlab_instance_url",
50+
models.URLField(max_length=200),
51+
),
52+
(
53+
"access_token",
54+
models.CharField(max_length=300),
55+
),
56+
(
57+
"project",
58+
models.OneToOneField(
59+
on_delete=django.db.models.deletion.CASCADE,
60+
related_name="gitlab_config",
61+
to="projects.project",
62+
),
63+
),
64+
],
65+
options={
66+
"abstract": False,
67+
},
68+
),
69+
]

api/integrations/gitlab/migrations/__init__.py

Whitespace-only changes.

api/integrations/gitlab/models.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from django.db import models
2+
3+
from core.models import SoftDeleteExportableModel
4+
5+
6+
class GitLabConfiguration(SoftDeleteExportableModel):
7+
project = models.OneToOneField(
8+
"projects.Project",
9+
on_delete=models.CASCADE,
10+
related_name="gitlab_config",
11+
)
12+
gitlab_instance_url = models.URLField(max_length=200)
13+
access_token = models.CharField(max_length=300)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from typing import Any
2+
3+
from integrations.common.serializers import BaseProjectIntegrationModelSerializer
4+
from integrations.gitlab.models import GitLabConfiguration
5+
6+
WRITE_ONLY_PLACEHOLDER = "write-only"
7+
8+
9+
class GitLabConfigurationSerializer(BaseProjectIntegrationModelSerializer):
10+
class Meta:
11+
model = GitLabConfiguration
12+
fields = ("id", "gitlab_instance_url", "access_token")
13+
14+
def to_representation(self, instance: GitLabConfiguration) -> dict[str, Any]:
15+
data = super().to_representation(instance)
16+
data["access_token"] = WRITE_ONLY_PLACEHOLDER
17+
return data

api/integrations/gitlab/views.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import structlog
2+
3+
from integrations.common.views import ProjectIntegrationBaseViewSet
4+
from integrations.gitlab.models import GitLabConfiguration
5+
from integrations.gitlab.serializers import GitLabConfigurationSerializer
6+
7+
logger = structlog.get_logger("gitlab")
8+
9+
10+
class GitLabConfigurationViewSet(ProjectIntegrationBaseViewSet):
11+
serializer_class = GitLabConfigurationSerializer # type: ignore[assignment]
12+
model_class = GitLabConfiguration # type: ignore[assignment]
13+
pagination_class = None
14+
15+
def _log_for(
16+
self, instance: GitLabConfiguration
17+
) -> structlog.typing.FilteringBoundLogger:
18+
return logger.bind( # type: ignore[no-any-return]
19+
project__id=instance.project.id,
20+
organisation__id=instance.project.organisation_id,
21+
)
22+
23+
def perform_create(self, serializer: GitLabConfigurationSerializer) -> None: # type: ignore[override]
24+
super().perform_create(serializer)
25+
instance: GitLabConfiguration = serializer.instance # type: ignore[assignment]
26+
self._log_for(instance).info(
27+
"gitlab-configuration-created",
28+
gitlab_instance_url=instance.gitlab_instance_url,
29+
)
30+
31+
def perform_update(self, serializer: GitLabConfigurationSerializer) -> None: # type: ignore[override]
32+
super().perform_update(serializer)
33+
instance: GitLabConfiguration = serializer.instance # type: ignore[assignment]
34+
self._log_for(instance).info(
35+
"gitlab-configuration-updated",
36+
gitlab_instance_url=instance.gitlab_instance_url,
37+
)
38+
39+
def perform_destroy(self, instance: GitLabConfiguration) -> None:
40+
log = self._log_for(instance)
41+
super().perform_destroy(instance)
42+
log.info("gitlab-configuration-deleted")

api/projects/urls.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from features.multivariate.views import MultivariateFeatureOptionViewSet
2020
from features.views import FeatureViewSet
2121
from integrations.datadog.views import DataDogConfigurationViewSet
22+
from integrations.gitlab.views import GitLabConfigurationViewSet
2223
from integrations.grafana.views import GrafanaProjectConfigurationViewSet
2324
from integrations.launch_darkly.views import LaunchDarklyImportRequestViewSet
2425
from integrations.new_relic.views import NewRelicConfigurationViewSet
@@ -65,6 +66,11 @@
6566
LaunchDarklyImportRequestViewSet,
6667
basename="imports-launch-darkly",
6768
)
69+
projects_router.register(
70+
r"integrations/gitlab",
71+
GitLabConfigurationViewSet,
72+
basename="integrations-gitlab",
73+
)
6874
projects_router.register(
6975
r"integrations/grafana",
7076
GrafanaProjectConfigurationViewSet,

api/tests/unit/integrations/gitlab/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)