From 043221f6d6cc6e25039619787089cdd6d2bf3233 Mon Sep 17 00:00:00 2001 From: John Joyce Date: Fri, 24 May 2024 14:03:05 -0700 Subject: [PATCH] feat(graphql): Support tagging incidents and assertions via GraphQL API (#10575) Co-authored-by: John Joyce Co-authored-by: John Joyce --- .../types/assertion/AssertionMapper.java | 11 +++++++++ .../types/assertion/AssertionType.java | 4 +++- .../types/incident/IncidentMapper.java | 12 ++++++++++ .../graphql/types/incident/IncidentType.java | 3 ++- .../src/main/resources/entity.graphql | 5 ++++ .../src/main/resources/incident.graphql | 5 ++++ .../types/incident/IncidentMapperTest.java | 23 ++++++++++++++++++- .../src/graphql/assertion.graphql | 3 +++ .../src/graphql/incident.graphql | 3 +++ .../src/main/resources/entity-registry.yml | 2 ++ 10 files changed, 68 insertions(+), 3 deletions(-) diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/assertion/AssertionMapper.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/assertion/AssertionMapper.java index c6f80f1d2cf47..ca13792b1e92b 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/assertion/AssertionMapper.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/assertion/AssertionMapper.java @@ -1,7 +1,10 @@ package com.linkedin.datahub.graphql.types.assertion; +import static com.linkedin.metadata.Constants.GLOBAL_TAGS_ASPECT_NAME; + import com.linkedin.assertion.AssertionInfo; import com.linkedin.common.DataPlatformInstance; +import com.linkedin.common.GlobalTags; import com.linkedin.common.Status; import com.linkedin.common.urn.Urn; import com.linkedin.data.DataMap; @@ -20,6 +23,7 @@ import com.linkedin.datahub.graphql.generated.SchemaFieldRef; import com.linkedin.datahub.graphql.types.common.mappers.DataPlatformInstanceAspectMapper; import com.linkedin.datahub.graphql.types.common.mappers.StringMapMapper; +import com.linkedin.datahub.graphql.types.tag.mappers.GlobalTagsMapper; import com.linkedin.entity.EntityResponse; import com.linkedin.entity.EnvelopedAspect; import com.linkedin.entity.EnvelopedAspectMap; @@ -62,6 +66,13 @@ public static Assertion map(@Nullable QueryContext context, final EntityResponse result.setStatus(mapStatus(new Status(envelopedStatus.getValue().data()))); } + final EnvelopedAspect envelopedTags = aspects.get(GLOBAL_TAGS_ASPECT_NAME); + if (envelopedTags != null) { + result.setTags( + GlobalTagsMapper.map( + context, new GlobalTags(envelopedTags.getValue().data()), entityUrn)); + } + return result; } diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/assertion/AssertionType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/assertion/AssertionType.java index 5e04520e84ab8..0cf74439132fe 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/assertion/AssertionType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/assertion/AssertionType.java @@ -27,7 +27,9 @@ public class AssertionType ImmutableSet.of( Constants.ASSERTION_KEY_ASPECT_NAME, Constants.ASSERTION_INFO_ASPECT_NAME, - Constants.DATA_PLATFORM_INSTANCE_ASPECT_NAME); + Constants.DATA_PLATFORM_INSTANCE_ASPECT_NAME, + Constants.GLOBAL_TAGS_ASPECT_NAME); + private final EntityClient _entityClient; public AssertionType(final EntityClient entityClient) { diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/incident/IncidentMapper.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/incident/IncidentMapper.java index c2aae4bd27d54..f39549fdc6eed 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/incident/IncidentMapper.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/incident/IncidentMapper.java @@ -1,5 +1,8 @@ package com.linkedin.datahub.graphql.types.incident; +import static com.linkedin.metadata.Constants.GLOBAL_TAGS_ASPECT_NAME; + +import com.linkedin.common.GlobalTags; import com.linkedin.common.urn.Urn; import com.linkedin.data.template.GetMode; import com.linkedin.datahub.graphql.QueryContext; @@ -12,6 +15,7 @@ import com.linkedin.datahub.graphql.generated.IncidentType; import com.linkedin.datahub.graphql.types.common.mappers.AuditStampMapper; import com.linkedin.datahub.graphql.types.common.mappers.UrnToEntityMapper; +import com.linkedin.datahub.graphql.types.tag.mappers.GlobalTagsMapper; import com.linkedin.entity.EntityResponse; import com.linkedin.entity.EnvelopedAspect; import com.linkedin.entity.EnvelopedAspectMap; @@ -50,6 +54,14 @@ public static Incident map(@Nullable QueryContext context, final EntityResponse } else { throw new RuntimeException(String.format("Incident does not exist!. urn: %s", entityUrn)); } + + final EnvelopedAspect envelopedTags = aspects.get(GLOBAL_TAGS_ASPECT_NAME); + if (envelopedTags != null) { + result.setTags( + GlobalTagsMapper.map( + context, new GlobalTags(envelopedTags.getValue().data()), entityUrn)); + } + return result; } diff --git a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/incident/IncidentType.java b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/incident/IncidentType.java index 414ba49d1eb76..780a19e8fae18 100644 --- a/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/incident/IncidentType.java +++ b/datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/types/incident/IncidentType.java @@ -23,7 +23,8 @@ public class IncidentType implements com.linkedin.datahub.graphql.types.EntityType { - static final Set ASPECTS_TO_FETCH = ImmutableSet.of(Constants.INCIDENT_INFO_ASPECT_NAME); + static final Set ASPECTS_TO_FETCH = + ImmutableSet.of(Constants.INCIDENT_INFO_ASPECT_NAME, Constants.GLOBAL_TAGS_ASPECT_NAME); private final EntityClient _entityClient; public IncidentType(final EntityClient entityClient) { diff --git a/datahub-graphql-core/src/main/resources/entity.graphql b/datahub-graphql-core/src/main/resources/entity.graphql index 2afb42c649fec..de030f77b0b01 100644 --- a/datahub-graphql-core/src/main/resources/entity.graphql +++ b/datahub-graphql-core/src/main/resources/entity.graphql @@ -7293,6 +7293,11 @@ type Assertion implements EntityWithRelationships & Entity { """ status: Status + """ + The standard tags for the Assertion + """ + tags: GlobalTags + """ Experimental API. For fetching extra aspects that do not have custom UI code yet diff --git a/datahub-graphql-core/src/main/resources/incident.graphql b/datahub-graphql-core/src/main/resources/incident.graphql index c3f4f35be608d..f7060b3ae8f67 100644 --- a/datahub-graphql-core/src/main/resources/incident.graphql +++ b/datahub-graphql-core/src/main/resources/incident.graphql @@ -107,6 +107,11 @@ type Incident implements Entity { """ created: AuditStamp! + """ + The standard tags for the Incident + """ + tags: GlobalTags + """ List of relationships between the source Entity and some destination entities with a given types """ diff --git a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/types/incident/IncidentMapperTest.java b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/types/incident/IncidentMapperTest.java index 8cce03389debb..0e2b78a9368ee 100644 --- a/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/types/incident/IncidentMapperTest.java +++ b/datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/types/incident/IncidentMapperTest.java @@ -3,8 +3,12 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; +import com.google.common.collect.ImmutableMap; import com.linkedin.common.AuditStamp; +import com.linkedin.common.GlobalTags; +import com.linkedin.common.TagAssociationArray; import com.linkedin.common.UrnArray; +import com.linkedin.common.urn.TagUrn; import com.linkedin.common.urn.Urn; import com.linkedin.data.template.SetMode; import com.linkedin.datahub.graphql.generated.EntityType; @@ -64,9 +68,22 @@ public void testMap() throws Exception { incidentInfo.setCreated(created); envelopedIncidentInfo.setValue(new Aspect(incidentInfo.data())); + + EnvelopedAspect envelopedTagsAspect = new EnvelopedAspect(); + GlobalTags tags = new GlobalTags(); + tags.setTags( + new TagAssociationArray( + new TagAssociationArray( + Collections.singletonList( + new com.linkedin.common.TagAssociation() + .setTag(TagUrn.createFromString("urn:li:tag:test")))))); + envelopedTagsAspect.setValue(new Aspect(tags.data())); + entityResponse.setAspects( new EnvelopedAspectMap( - Collections.singletonMap(Constants.INCIDENT_INFO_ASPECT_NAME, envelopedIncidentInfo))); + ImmutableMap.of( + Constants.INCIDENT_INFO_ASPECT_NAME, envelopedIncidentInfo, + Constants.GLOBAL_TAGS_ASPECT_NAME, envelopedTagsAspect))); Incident incident = IncidentMapper.map(null, entityResponse); @@ -92,5 +109,9 @@ public void testMap() throws Exception { assertEquals(incident.getStatus().getLastUpdated().getActor(), userUrn.toString()); assertEquals(incident.getCreated().getTime().longValue(), 1000L); assertEquals(incident.getCreated().getActor(), userUrn.toString()); + + assertEquals(incident.getTags().getTags().size(), 1); + assertEquals( + incident.getTags().getTags().get(0).getTag().getUrn().toString(), "urn:li:tag:test"); } } diff --git a/datahub-web-react/src/graphql/assertion.graphql b/datahub-web-react/src/graphql/assertion.graphql index 0b64c4c8d6ddd..016e8a4f06086 100644 --- a/datahub-web-react/src/graphql/assertion.graphql +++ b/datahub-web-react/src/graphql/assertion.graphql @@ -48,6 +48,9 @@ fragment assertionDetails on Assertion { } description } + tags { + ...globalTagsFields + } } fragment assertionRunEventDetails on AssertionRunEvent { diff --git a/datahub-web-react/src/graphql/incident.graphql b/datahub-web-react/src/graphql/incident.graphql index ef0cf74819361..3ee18df9d6e94 100644 --- a/datahub-web-react/src/graphql/incident.graphql +++ b/datahub-web-react/src/graphql/incident.graphql @@ -24,6 +24,9 @@ fragment incidentsFields on EntityIncidentsResult { time actor } + tags { + ...globalTagsFields + } } } diff --git a/metadata-models/src/main/resources/entity-registry.yml b/metadata-models/src/main/resources/entity-registry.yml index 60ef05ea55b2c..fe6063b3cefc6 100644 --- a/metadata-models/src/main/resources/entity-registry.yml +++ b/metadata-models/src/main/resources/entity-registry.yml @@ -295,6 +295,7 @@ entities: - assertionRunEvent - assertionActions - status + - globalTags - name: dataHubRetention category: internal keyAspect: dataHubRetentionKey @@ -464,6 +465,7 @@ entities: keyAspect: incidentKey aspects: - incidentInfo + - globalTags - name: dataHubRole category: core keyAspect: dataHubRoleKey