Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: HEXA-1122 list of templates in create pipeline dialog #885

Merged
merged 61 commits into from
Dec 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
d66ea09
Create app
YolanFery Dec 12, 2024
4c5dbf6
Model v1
YolanFery Dec 12, 2024
a7c17d0
Mutations v1
YolanFery Dec 12, 2024
402081f
CreateTemplateResolver
YolanFery Dec 12, 2024
556ad64
Permissisions
YolanFery Dec 12, 2024
a13635a
Unique constraint
YolanFery Dec 12, 2024
78ce40b
GraphQL setup
YolanFery Dec 12, 2024
3bb1fd1
Directory cleanup
YolanFery Dec 12, 2024
981624c
Directory cleanup
YolanFery Dec 12, 2024
f376e7f
Admin
YolanFery Dec 12, 2024
ac3e75a
first test
YolanFery Dec 12, 2024
0875497
First db migration
YolanFery Dec 12, 2024
7173eec
Create version conditionnaly
YolanFery Dec 12, 2024
adde629
Refactor mutations.py
YolanFery Dec 12, 2024
20eca83
Move template creation to Pipeline model
YolanFery Dec 12, 2024
e68b558
Small unit test for version creation
YolanFery Dec 12, 2024
61d0677
Fix
YolanFery Dec 12, 2024
2a74949
Test get or create template
YolanFery Dec 12, 2024
37074a5
Schema test v0
YolanFery Dec 12, 2024
feb352a
Graphql test v1
YolanFery Dec 12, 2024
2092bef
Graphql test v1
YolanFery Dec 12, 2024
621754e
Fix circular dep
YolanFery Dec 12, 2024
1800389
Fix unit tests
YolanFery Dec 12, 2024
e59d6ab
Fix checking existing template
YolanFery Dec 12, 2024
5c522f9
Schema and small fix in test
YolanFery Dec 12, 2024
c59b113
Schema
YolanFery Dec 12, 2024
ebb37e2
Add to schema
YolanFery Dec 12, 2024
1210fff
Docuemtn schema
YolanFery Dec 12, 2024
73db3a4
Fix permission types
YolanFery Dec 12, 2024
f5cbc5d
Improvements
YolanFery Dec 12, 2024
27955c6
Fix bug
YolanFery Dec 12, 2024
40a3ba5
Fix bug and remove paging
YolanFery Dec 12, 2024
0afb591
Complete test
YolanFery Dec 12, 2024
6516ff4
Change migration
YolanFery Dec 12, 2024
11e6acd
Change migration
YolanFery Dec 12, 2024
fc98309
Schema
YolanFery Dec 16, 2024
f5eba06
Fix in case of missing
YolanFery Dec 16, 2024
e3ce3a0
Rename folder
YolanFery Dec 17, 2024
cf55d1c
Renames
YolanFery Dec 17, 2024
e429424
Renames
YolanFery Dec 17, 2024
9d8617c
Renames
YolanFery Dec 17, 2024
a0d724f
Renames
YolanFery Dec 17, 2024
16173fb
Migration
YolanFery Dec 17, 2024
135d8d3
Fix
YolanFery Dec 17, 2024
6ffbbb2
Fix
YolanFery Dec 17, 2024
49d27c7
Fix
YolanFery Dec 17, 2024
7fb0092
Fix bug
YolanFery Dec 17, 2024
753ea1c
Fix schema
YolanFery Dec 17, 2024
f073622
Fix schema
YolanFery Dec 17, 2024
667ddbd
Fix migration
YolanFery Dec 17, 2024
d5b096e
Fix test
YolanFery Dec 17, 2024
2f6443e
Query all templates
YolanFery Dec 17, 2024
d9ea7e2
PageList
YolanFery Dec 19, 2024
5b3ed04
Merge
YolanFery Dec 20, 2024
c34e404
Migration script
YolanFery Dec 20, 2024
588b877
Merge
YolanFery Dec 24, 2024
ae40db5
Fix unparsable code
YolanFery Dec 24, 2024
0a376d1
Fix test
YolanFery Dec 24, 2024
fbe343b
Add search functionnality
YolanFery Dec 27, 2024
2217c98
Add search functionnality
YolanFery Dec 27, 2024
476077f
Update hexa/pipeline_templates/schema/queries.py
YolanFery Dec 30, 2024
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
17 changes: 16 additions & 1 deletion hexa/pipeline_templates/graphql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@ extend type Mutation {
createPipelineFromTemplateVersion(input: CreatePipelineFromTemplateVersionInput!): CreatePipelineFromTemplateVersionResult! @loginRequired
}

extend type Query {
pipelineTemplates(page: Int = 1, perPage: Int = 15, search: String): PipelineTemplatePage! # Returns pipeline templates.
}

"""
Represents paged result of fetching pipeline templates.
"""
type PipelineTemplatePage {
pageNumber: Int!
totalPages: Int!
totalItems: Int!
items: [PipelineTemplate!]!
}
"""
Represents the input for creating a new pipeline template version.
"""
Expand Down Expand Up @@ -75,6 +88,8 @@ type PipelineTemplate {
description: String # The description of the pipeline template.
config: String # The configuration of the pipeline template.
versions: [PipelineTemplateVersion!] # The list of versions of the pipeline template.
currentVersion: PipelineTemplateVersion # The current version of the pipeline template.
sourcePipeline: Pipeline # The source pipeline of the pipeline template.
}

"""
Expand All @@ -83,7 +98,7 @@ Represents a version of a pipeline template.
type PipelineTemplateVersion {
id: UUID! # The ID of the pipeline template version.
versionNumber: Int! # The version number of the pipeline template version.
createdAt: String! # The creation date of the pipeline template version.
createdAt: DateTime! # The creation date of the pipeline template version.
template: PipelineTemplate! # The pipeline template associated with the version.
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Generated by Django 4.2.17 on 2024-12-20 13:05

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("pipeline_templates", "0002_alter_pipelinetemplate_name"),
]

operations = [
migrations.AlterModelOptions(
name="pipelinetemplate",
options={"ordering": ["name"]},
),
]
7 changes: 6 additions & 1 deletion hexa/pipeline_templates/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class Meta:
condition=Q(deleted_at__isnull=True),
),
]
ordering = ["name"]

id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
created_at = models.DateTimeField(auto_now_add=True)
Expand All @@ -59,6 +60,10 @@ def create_version(self, source_pipeline_version):
)
return template_version

@property
def last_version(self) -> "PipelineTemplateVersion":
return self.versions.last()

def __str__(self):
return self.name

Expand Down Expand Up @@ -102,7 +107,7 @@ def create_pipeline(self, code, workspace, user):
source_template=self.template,
code=code,
name=source_pipeline.name,
description=source_pipeline.description,
description=self.template.description,
config=source_pipeline.config,
workspace=workspace,
)
Expand Down
2 changes: 1 addition & 1 deletion hexa/pipeline_templates/schema/mutations.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def resolve_create_pipeline_from_template_version(_, info, **kwargs):
except PipelineTemplateVersion.DoesNotExist:
return {"success": False, "errors": ["PIPELINE_TEMPLATE_VERSION_NOT_FOUND"]}

pipeline_code = f"{template_version.template.source_pipeline.code} (from Template)"
pipeline_code = template_version.template.source_pipeline.code
if Pipeline.objects.filter(workspace=workspace, code=pipeline_code).exists():
return {"success": False, "errors": ["PIPELINE_ALREADY_EXISTS"]}
pipeline = template_version.create_pipeline(pipeline_code, workspace, request.user)
Expand Down
16 changes: 16 additions & 0 deletions hexa/pipeline_templates/schema/queries.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
from ariadne import QueryType

from hexa.core.graphql import result_page
from hexa.pipeline_templates.models import PipelineTemplate

pipeline_template_query = QueryType()


@pipeline_template_query.field("pipelineTemplates")
def resolve_pipeline_templates(_, info, **kwargs):
search = kwargs.get("search", "")
pipeline_templates = PipelineTemplate.objects.filter(name__icontains=search)

return result_page(
pipeline_templates,
page=kwargs.get("page", 1),
per_page=kwargs.get("per_page", 15),
)


bindables = [
pipeline_template_query,
]
14 changes: 14 additions & 0 deletions hexa/pipeline_templates/schema/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,20 @@ def resolve_pipeline_template_versions(
return pipeline_template.versions.all()


@pipeline_template_object.field("currentVersion")
def resolve_pipeline_template_current_version(
pipeline_template: PipelineTemplate, info, **kwargs
):
return pipeline_template.last_version


@pipeline_template_object.field("sourcePipeline")
def resolve_pipeline_template_source_pipeline(
pipeline_template: PipelineTemplate, info, **kwargs
):
return pipeline_template.source_pipeline


bindables = [
pipeline_template_object,
pipeline_template_permissions,
Expand Down
124 changes: 116 additions & 8 deletions hexa/pipeline_templates/tests/test_schema/test_templates.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from unittest.mock import patch

from hexa.core.test import GraphQLTestCase
from hexa.pipeline_templates.models import PipelineTemplate
from hexa.pipelines.models import (
Pipeline,
PipelineVersion,
Expand All @@ -13,7 +14,9 @@

class PipelineTemplatesTest(GraphQLTestCase):
USER_ROOT = None
PIPELINE = None
PIPELINE1 = None
PIPELINE2 = None
PIPELINE3 = None
PIPELINE_VERSION1 = None
PIPELINE_VERSION2 = None

Expand All @@ -32,22 +35,33 @@ def setUpTestData(cls):
name="WS1",
description="Workspace 1",
)
cls.PIPELINE = Pipeline.objects.create(
cls.WS2 = Workspace.objects.create_if_has_perm(
cls.USER_ROOT,
name="WS2",
description="Workspace 2",
)
cls.PIPELINE1 = Pipeline.objects.create(
name="Test Pipeline", code="Test Pipeline", workspace=cls.WS1
)
cls.PIPELINE_VERSION1 = PipelineVersion.objects.create(
pipeline=cls.PIPELINE,
pipeline=cls.PIPELINE1,
version_number=1,
description="Initial version",
parameters=[{"code": "param_1"}],
config=[{"param_1": 1}],
zipfile=str.encode("some_bytes"),
)
cls.PIPELINE_VERSION2 = PipelineVersion.objects.create(
pipeline=cls.PIPELINE,
pipeline=cls.PIPELINE1,
version_number=2,
description="Second version",
)
cls.PIPELINE2 = Pipeline.objects.create(
name="Pipeline 2", code="pipeline-2", workspace=cls.WS1
)
cls.PIPELINE3 = Pipeline.objects.create(
name="Pipeline 3", code="pipeline-3", workspace=cls.WS1
)

def create_template_version(self, pipeline_version_id, expected_versions):
r = self.run_query(
Expand All @@ -65,7 +79,7 @@ def create_template_version(self, pipeline_version_id, expected_versions):
"description": "A test template",
"config": "{}",
"workspaceSlug": self.WS1.slug,
"pipelineId": str(self.PIPELINE.id),
"pipelineId": str(self.PIPELINE1.id),
"pipelineVersionId": str(pipeline_version_id),
}
},
Expand Down Expand Up @@ -103,7 +117,7 @@ def test_create_pipeline_from_template_version(self):
""",
{
"input": {
"workspaceSlug": self.WS1.slug,
"workspaceSlug": self.WS2.slug,
"pipelineTemplateVersionId": str(
self.PIPELINE_VERSION1.template_version.id
),
Expand All @@ -115,8 +129,8 @@ def test_create_pipeline_from_template_version(self):
"success": True,
"errors": [],
"pipeline": {
"name": self.PIPELINE.name,
"code": "Test Pipeline (from Template)",
"name": self.PIPELINE1.name,
"code": "Test Pipeline",
"currentVersion": {
"zipfile": "c29tZV9ieXRlcw==",
"parameters": [{"code": "param_1", "default": None}],
Expand Down Expand Up @@ -152,3 +166,97 @@ def test_create_pipeline_from_template_version(self):
},
r["data"]["createPipelineFromTemplateVersion"],
)

def test_get_pipeline_templates(self):
PipelineTemplate.objects.create(
name="Template 1", code="Code 1", source_pipeline=self.PIPELINE1
)
PipelineTemplate.objects.create(
name="Template 2", code="Code 2", source_pipeline=self.PIPELINE2
)
r = self.run_query(
"""
query {
pipelineTemplates(page: 1, perPage: 1) {
pageNumber
totalPages
totalItems
items {
name
code
}
}
}
"""
)
self.assertEqual(
{
"pageNumber": 1,
"totalPages": 2,
"totalItems": 2,
"items": [{"code": "Code 1", "name": "Template 1"}],
},
r["data"]["pipelineTemplates"],
)

def test_searching_pipeline_templates(self):
PipelineTemplate.objects.create(
name="Template 1", code="Code 1", source_pipeline=self.PIPELINE1
)
PipelineTemplate.objects.create(
name="Template 2", code="Code 2", source_pipeline=self.PIPELINE2
)
PipelineTemplate.objects.create(
name="Template 22", code="Code 22", source_pipeline=self.PIPELINE3
)
r = self.run_query(
"""
query {
pipelineTemplates(page: 1, perPage: 1, search: "Template 3") {
pageNumber
totalPages
totalItems
items {
name
code
}
}
}
"""
)
self.assertEqual(
{
"pageNumber": 1,
"totalPages": 1,
"totalItems": 0,
"items": [],
},
r["data"]["pipelineTemplates"],
)
r = self.run_query(
"""
query {
pipelineTemplates(page: 1, perPage: 2, search: "Template 2") {
pageNumber
totalPages
totalItems
items {
name
code
}
}
}
"""
)
self.assertEqual(
{
"pageNumber": 1,
"totalPages": 1,
"totalItems": 2,
"items": [
{"code": "Code 2", "name": "Template 2"},
{"code": "Code 22", "name": "Template 22"},
],
},
r["data"]["pipelineTemplates"],
)
Loading