Skip to content

Commit e25fe4b

Browse files
Merge branch 'master' into Qlik-Connector-Integration
2 parents 224b656 + 62f2789 commit e25fe4b

File tree

209 files changed

+6651
-3017
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

209 files changed

+6651
-3017
lines changed

.github/workflows/docker-unified.yml

-8
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,9 @@ on:
33
push:
44
branches:
55
- master
6-
paths-ignore:
7-
- "docs-website/**"
8-
- "docs/**"
9-
- "**.md"
106
pull_request:
117
branches:
128
- "**"
13-
paths-ignore:
14-
- "docs-website/**"
15-
- "docs/**"
16-
- "**.md"
179
release:
1810
types: [published]
1911

build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ plugins {
7373
id 'com.gorylenko.gradle-git-properties' version '2.4.1'
7474
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false
7575
id 'com.palantir.docker' version '0.35.0' apply false
76-
id 'com.avast.gradle.docker-compose' version '0.17.5'
76+
id 'com.avast.gradle.docker-compose' version '0.17.6'
7777
id "com.diffplug.spotless" version "6.23.3"
7878
// https://blog.ltgt.net/javax-jakarta-mess-and-gradle-solution/
7979
// TODO id "org.gradlex.java-ecosystem-capabilities" version "1.0"

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/GmsGraphQLEngine.java

+2
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@
141141
import com.linkedin.datahub.graphql.resolvers.entity.EntityExistsResolver;
142142
import com.linkedin.datahub.graphql.resolvers.entity.EntityPrivilegesResolver;
143143
import com.linkedin.datahub.graphql.resolvers.form.BatchAssignFormResolver;
144+
import com.linkedin.datahub.graphql.resolvers.form.BatchRemoveFormResolver;
144145
import com.linkedin.datahub.graphql.resolvers.form.CreateDynamicFormAssignmentResolver;
145146
import com.linkedin.datahub.graphql.resolvers.form.IsFormAssignedToMeResolver;
146147
import com.linkedin.datahub.graphql.resolvers.form.SubmitFormPromptResolver;
@@ -1214,6 +1215,7 @@ private void configureMutationResolvers(final RuntimeWiring.Builder builder) {
12141215
new CreateDynamicFormAssignmentResolver(this.formService))
12151216
.dataFetcher(
12161217
"verifyForm", new VerifyFormResolver(this.formService, this.groupService))
1218+
.dataFetcher("batchRemoveForm", new BatchRemoveFormResolver(this.formService))
12171219
.dataFetcher("raiseIncident", new RaiseIncidentResolver(this.entityClient))
12181220
.dataFetcher(
12191221
"updateIncidentStatus",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.linkedin.datahub.graphql.resolvers.form;
2+
3+
import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.bindArgument;
4+
5+
import com.datahub.authentication.Authentication;
6+
import com.linkedin.common.urn.Urn;
7+
import com.linkedin.common.urn.UrnUtils;
8+
import com.linkedin.datahub.graphql.QueryContext;
9+
import com.linkedin.datahub.graphql.generated.BatchAssignFormInput;
10+
import com.linkedin.metadata.service.FormService;
11+
import graphql.schema.DataFetcher;
12+
import graphql.schema.DataFetchingEnvironment;
13+
import java.util.List;
14+
import java.util.Objects;
15+
import java.util.concurrent.CompletableFuture;
16+
import java.util.stream.Collectors;
17+
import javax.annotation.Nonnull;
18+
19+
public class BatchRemoveFormResolver implements DataFetcher<CompletableFuture<Boolean>> {
20+
21+
private final FormService _formService;
22+
23+
public BatchRemoveFormResolver(@Nonnull final FormService formService) {
24+
_formService = Objects.requireNonNull(formService, "formService must not be null");
25+
}
26+
27+
@Override
28+
public CompletableFuture<Boolean> get(final DataFetchingEnvironment environment)
29+
throws Exception {
30+
final QueryContext context = environment.getContext();
31+
32+
final BatchAssignFormInput input =
33+
bindArgument(environment.getArgument("input"), BatchAssignFormInput.class);
34+
final Urn formUrn = UrnUtils.getUrn(input.getFormUrn());
35+
final List<String> entityUrns = input.getEntityUrns();
36+
final Authentication authentication = context.getAuthentication();
37+
38+
// TODO: (PRD-1062) Add permission check once permission exists
39+
40+
return CompletableFuture.supplyAsync(
41+
() -> {
42+
try {
43+
_formService.batchUnassignFormForEntities(
44+
entityUrns.stream().map(UrnUtils::getUrn).collect(Collectors.toList()),
45+
formUrn,
46+
authentication);
47+
return true;
48+
} catch (Exception e) {
49+
throw new RuntimeException(
50+
String.format("Failed to perform update against input %s", input), e);
51+
}
52+
});
53+
}
54+
}

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/search/SearchAcrossLineageResolver.java

+11-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import com.google.common.collect.ImmutableSet;
88
import com.linkedin.common.urn.Urn;
9+
import com.linkedin.datahub.graphql.generated.AndFilterInput;
910
import com.linkedin.datahub.graphql.generated.EntityType;
1011
import com.linkedin.datahub.graphql.generated.FacetFilterInput;
1112
import com.linkedin.datahub.graphql.generated.LineageDirection;
@@ -92,9 +93,14 @@ public CompletableFuture<SearchAcrossLineageResults> get(DataFetchingEnvironment
9293

9394
final int start = input.getStart() != null ? input.getStart() : DEFAULT_START;
9495
final int count = input.getCount() != null ? input.getCount() : DEFAULT_COUNT;
95-
final List<FacetFilterInput> filters =
96-
input.getFilters() != null ? input.getFilters() : new ArrayList<>();
97-
final Integer maxHops = getMaxHops(filters);
96+
final List<AndFilterInput> filters =
97+
input.getOrFilters() != null ? input.getOrFilters() : new ArrayList<>();
98+
final List<FacetFilterInput> facetFilters =
99+
filters.stream()
100+
.map(AndFilterInput::getAnd)
101+
.flatMap(List::stream)
102+
.collect(Collectors.toList());
103+
final Integer maxHops = getMaxHops(facetFilters);
98104

99105
@Nullable
100106
final Long startTimeMillis =
@@ -117,7 +123,8 @@ public CompletableFuture<SearchAcrossLineageResults> get(DataFetchingEnvironment
117123
start,
118124
count);
119125

120-
final Filter filter = ResolverUtils.buildFilter(filters, input.getOrFilters());
126+
final Filter filter =
127+
ResolverUtils.buildFilter(input.getFilters(), input.getOrFilters());
121128
SearchFlags searchFlags = null;
122129
com.linkedin.datahub.graphql.generated.SearchFlags inputFlags = input.getSearchFlags();
123130
if (inputFlags != null) {

datahub-graphql-core/src/main/resources/forms.graphql

+22
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
extend type Mutation {
2+
"""
3+
Remove a form from a given list of entities.
4+
"""
5+
batchRemoveForm(input: BatchRemoveFormInput!): Boolean!
6+
}
7+
18
"""
29
Requirements forms that are assigned to an entity.
310
"""
@@ -376,3 +383,18 @@ input VerifyFormInput {
376383
"""
377384
entityUrn: String!
378385
}
386+
387+
"""
388+
Input for batch removing a form from different entities
389+
"""
390+
input BatchRemoveFormInput {
391+
"""
392+
The urn of the form being removed from entities
393+
"""
394+
formUrn: String!
395+
396+
"""
397+
The entities that this form is being removed from
398+
"""
399+
entityUrns: [String!]!
400+
}

datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/TestUtils.java

+10-10
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import com.linkedin.data.schema.annotation.PathSpecBasedSchemaAnnotationVisitor;
1414
import com.linkedin.metadata.entity.EntityService;
1515
import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl;
16-
import com.linkedin.metadata.entity.ebean.batch.MCPUpsertBatchItem;
16+
import com.linkedin.metadata.entity.ebean.batch.ChangeItemImpl;
1717
import com.linkedin.metadata.models.registry.ConfigEntityRegistry;
1818
import com.linkedin.metadata.models.registry.EntityRegistry;
1919
import com.linkedin.mxe.MetadataChangeProposal;
@@ -22,14 +22,14 @@
2222

2323
public class TestUtils {
2424

25-
public static EntityService<MCPUpsertBatchItem> getMockEntityService() {
25+
public static EntityService<ChangeItemImpl> getMockEntityService() {
2626
PathSpecBasedSchemaAnnotationVisitor.class
2727
.getClassLoader()
2828
.setClassAssertionStatus(PathSpecBasedSchemaAnnotationVisitor.class.getName(), false);
2929
EntityRegistry registry =
3030
new ConfigEntityRegistry(TestUtils.class.getResourceAsStream("/test-entity-registry.yaml"));
31-
EntityService<MCPUpsertBatchItem> mockEntityService =
32-
(EntityService<MCPUpsertBatchItem>) Mockito.mock(EntityService.class);
31+
EntityService<ChangeItemImpl> mockEntityService =
32+
(EntityService<ChangeItemImpl>) Mockito.mock(EntityService.class);
3333
Mockito.when(mockEntityService.getEntityRegistry()).thenReturn(registry);
3434
return mockEntityService;
3535
}
@@ -111,14 +111,14 @@ public static QueryContext getMockDenyContext(String actorUrn, AuthorizationRequ
111111
}
112112

113113
public static void verifyIngestProposal(
114-
EntityService<MCPUpsertBatchItem> mockService,
114+
EntityService<ChangeItemImpl> mockService,
115115
int numberOfInvocations,
116116
MetadataChangeProposal proposal) {
117117
verifyIngestProposal(mockService, numberOfInvocations, List.of(proposal));
118118
}
119119

120120
public static void verifyIngestProposal(
121-
EntityService<MCPUpsertBatchItem> mockService,
121+
EntityService<ChangeItemImpl> mockService,
122122
int numberOfInvocations,
123123
List<MetadataChangeProposal> proposals) {
124124
AspectsBatchImpl batch =
@@ -128,29 +128,29 @@ public static void verifyIngestProposal(
128128
}
129129

130130
public static void verifySingleIngestProposal(
131-
EntityService<MCPUpsertBatchItem> mockService,
131+
EntityService<ChangeItemImpl> mockService,
132132
int numberOfInvocations,
133133
MetadataChangeProposal proposal) {
134134
Mockito.verify(mockService, Mockito.times(numberOfInvocations))
135135
.ingestProposal(Mockito.eq(proposal), Mockito.any(AuditStamp.class), Mockito.eq(false));
136136
}
137137

138138
public static void verifyIngestProposal(
139-
EntityService<MCPUpsertBatchItem> mockService, int numberOfInvocations) {
139+
EntityService<ChangeItemImpl> mockService, int numberOfInvocations) {
140140
Mockito.verify(mockService, Mockito.times(numberOfInvocations))
141141
.ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.eq(false));
142142
}
143143

144144
public static void verifySingleIngestProposal(
145-
EntityService<MCPUpsertBatchItem> mockService, int numberOfInvocations) {
145+
EntityService<ChangeItemImpl> mockService, int numberOfInvocations) {
146146
Mockito.verify(mockService, Mockito.times(numberOfInvocations))
147147
.ingestProposal(
148148
Mockito.any(MetadataChangeProposal.class),
149149
Mockito.any(AuditStamp.class),
150150
Mockito.eq(false));
151151
}
152152

153-
public static void verifyNoIngestProposal(EntityService<MCPUpsertBatchItem> mockService) {
153+
public static void verifyNoIngestProposal(EntityService<ChangeItemImpl> mockService) {
154154
Mockito.verify(mockService, Mockito.times(0))
155155
.ingestProposal(Mockito.any(AspectsBatchImpl.class), Mockito.anyBoolean());
156156
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package com.linkedin.datahub.graphql.resolvers.form;
2+
3+
import static com.linkedin.datahub.graphql.TestUtils.getMockAllowContext;
4+
import static org.testng.Assert.assertThrows;
5+
import static org.testng.Assert.assertTrue;
6+
7+
import com.datahub.authentication.Authentication;
8+
import com.linkedin.common.urn.UrnUtils;
9+
import com.linkedin.datahub.graphql.QueryContext;
10+
import com.linkedin.datahub.graphql.generated.BatchAssignFormInput;
11+
import com.linkedin.metadata.service.FormService;
12+
import graphql.com.google.common.collect.ImmutableList;
13+
import graphql.schema.DataFetchingEnvironment;
14+
import java.util.concurrent.CompletionException;
15+
import org.mockito.Mockito;
16+
import org.testng.annotations.Test;
17+
18+
public class BatchRemoveFormResolverTest {
19+
20+
private static final String TEST_DATASET_URN =
21+
"urn:li:dataset:(urn:li:dataPlatform:hive,name,PROD)";
22+
private static final String TEST_FORM_URN = "urn:li:form:1";
23+
24+
private static final BatchAssignFormInput TEST_INPUT =
25+
new BatchAssignFormInput(TEST_FORM_URN, ImmutableList.of(TEST_DATASET_URN));
26+
27+
@Test
28+
public void testGetSuccess() throws Exception {
29+
FormService mockFormService = initMockFormService(true);
30+
BatchRemoveFormResolver resolver = new BatchRemoveFormResolver(mockFormService);
31+
32+
// Execute resolver
33+
QueryContext mockContext = getMockAllowContext();
34+
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
35+
Mockito.when(mockEnv.getArgument(Mockito.eq("input"))).thenReturn(TEST_INPUT);
36+
Mockito.when(mockEnv.getContext()).thenReturn(mockContext);
37+
38+
boolean success = resolver.get(mockEnv).get();
39+
40+
assertTrue(success);
41+
42+
// Validate that we called unassign on the service
43+
Mockito.verify(mockFormService, Mockito.times(1))
44+
.batchUnassignFormForEntities(
45+
Mockito.eq(ImmutableList.of(UrnUtils.getUrn(TEST_DATASET_URN))),
46+
Mockito.eq(UrnUtils.getUrn(TEST_FORM_URN)),
47+
Mockito.any(Authentication.class));
48+
}
49+
50+
@Test
51+
public void testThrowsError() throws Exception {
52+
FormService mockFormService = initMockFormService(false);
53+
BatchRemoveFormResolver resolver = new BatchRemoveFormResolver(mockFormService);
54+
55+
// Execute resolver
56+
QueryContext mockContext = getMockAllowContext();
57+
DataFetchingEnvironment mockEnv = Mockito.mock(DataFetchingEnvironment.class);
58+
Mockito.when(mockEnv.getArgument(Mockito.eq("input"))).thenReturn(TEST_INPUT);
59+
Mockito.when(mockEnv.getContext()).thenReturn(mockContext);
60+
61+
assertThrows(CompletionException.class, () -> resolver.get(mockEnv).join());
62+
63+
// Validate that we called unassign on the service - but it throws an error
64+
Mockito.verify(mockFormService, Mockito.times(1))
65+
.batchUnassignFormForEntities(
66+
Mockito.eq(ImmutableList.of(UrnUtils.getUrn(TEST_DATASET_URN))),
67+
Mockito.eq(UrnUtils.getUrn(TEST_FORM_URN)),
68+
Mockito.any(Authentication.class));
69+
}
70+
71+
private FormService initMockFormService(final boolean shouldSucceed) throws Exception {
72+
FormService service = Mockito.mock(FormService.class);
73+
74+
if (!shouldSucceed) {
75+
Mockito.doThrow(new RuntimeException())
76+
.when(service)
77+
.batchUnassignFormForEntities(
78+
Mockito.any(), Mockito.any(), Mockito.any(Authentication.class));
79+
}
80+
81+
return service;
82+
}
83+
}

datahub-graphql-core/src/test/java/com/linkedin/datahub/graphql/resolvers/tag/AddTagsResolverTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils;
1919
import com.linkedin.metadata.entity.EntityService;
2020
import com.linkedin.metadata.entity.ebean.batch.AspectsBatchImpl;
21-
import com.linkedin.metadata.entity.ebean.batch.MCPUpsertBatchItem;
21+
import com.linkedin.metadata.entity.ebean.batch.ChangeItemImpl;
2222
import com.linkedin.mxe.MetadataChangeProposal;
2323
import graphql.schema.DataFetchingEnvironment;
2424
import java.util.concurrent.CompletionException;
@@ -221,7 +221,7 @@ public void testGetUnauthorized() throws Exception {
221221

222222
@Test
223223
public void testGetEntityClientException() throws Exception {
224-
EntityService<MCPUpsertBatchItem> mockService = getMockEntityService();
224+
EntityService<ChangeItemImpl> mockService = getMockEntityService();
225225

226226
Mockito.doThrow(RuntimeException.class)
227227
.when(mockService)

datahub-upgrade/src/main/java/com/linkedin/datahub/upgrade/restorebackup/RestoreStorageStep.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,9 @@ private void readerExecutable(ReaderWrapper reader, UpgradeContext context) {
178178
final RecordTemplate aspectRecord;
179179
try {
180180
aspectRecord =
181-
EntityUtils.toAspectRecord(
182-
entityName, aspectName, aspect.getMetadata(), _entityRegistry);
181+
EntityUtils.toSystemAspect(aspect.toEntityAspect(), _entityService)
182+
.get()
183+
.getRecordTemplate();
183184
} catch (Exception e) {
184185
context
185186
.report()

0 commit comments

Comments
 (0)