Skip to content

Commit a326b80

Browse files
authored
Merge branch 'datahub-project:master' into master
2 parents 174fb12 + bb479db commit a326b80

File tree

32 files changed

+3449
-78
lines changed

32 files changed

+3449
-78
lines changed

.github/actionlint.yaml

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
self-hosted-runner:
2+
labels:
3+
- "depot-ubuntu-22.04-small"
4+
- "depot-ubuntu-22.04-4"
5+
- "depot-ubuntu-22.04"
6+
- "depot-ubuntu-24.04"
7+
- "depot-ubuntu-24.04-small"

.github/workflows/build-and-test.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ jobs:
158158
with:
159159
token: ${{ secrets.CODECOV_TOKEN }}
160160

161-
quickstart-compose-validation:
161+
docker-codegen-validation:
162162
runs-on: ubuntu-latest
163163
needs: setup
164164
if: ${{ needs.setup.outputs.docker_change == 'true' }}
@@ -170,6 +170,8 @@ jobs:
170170
python-version: "3.10"
171171
- name: Quickstart Compose Validation
172172
run: ./docker/quickstart/generate_and_compare.sh
173+
- name: Docker Snippet Validation
174+
run: python python-build/generate_ingestion_docker.py --check
173175

174176
event-file:
175177
runs-on: ubuntu-latest

.github/workflows/docker-unified.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1143,7 +1143,7 @@ jobs:
11431143
docker pull confluentinc/cp-kafka:7.4.0 &
11441144
docker pull mysql:8.2 &
11451145
docker pull opensearchproject/opensearch:2.9.0 &
1146-
docker pull ${{ env.DATAHUB_INGESTION_IMAGE }}:head &
1146+
docker pull ${{ env.DATAHUB_INGESTION_BASE_IMAGE }}:head-slim &
11471147
11481148
wait
11491149
docker images
@@ -1152,7 +1152,7 @@ jobs:
11521152
env:
11531153
DATAHUB_TELEMETRY_ENABLED: false
11541154
DATAHUB_VERSION: ${{ needs.setup.outputs.unique_tag }}
1155-
DATAHUB_ACTIONS_IMAGE: ${{ env.DATAHUB_INGESTION_IMAGE }}
1155+
DATAHUB_ACTIONS_IMAGE: ${{ env.DATAHUB_INGESTION_BASE_IMAGE }}
11561156
ACTIONS_VERSION: ${{ needs.datahub_ingestion_slim_build.outputs.tag || 'head-slim' }}
11571157
ACTIONS_EXTRA_PACKAGES: "acryl-datahub-actions[executor] acryl-datahub-actions"
11581158
ACTIONS_CONFIG: "https://raw.githubusercontent.com/acryldata/datahub-actions/main/docker/config/executor.yaml"

datahub-upgrade/src/main/java/com/linkedin/datahub/upgrade/system/ingestion/BackfillIngestionSourceInfoIndicesStep.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
@Slf4j
1616
public class BackfillIngestionSourceInfoIndicesStep extends AbstractMCLStep {
1717

18-
private static final String UPGRADE_ID = BackfillIngestionSourceInfoIndices.class.getSimpleName();
18+
private static final String UPGRADE_ID =
19+
BackfillIngestionSourceInfoIndices.class.getSimpleName() + "-v2";
1920
private static final Urn UPGRADE_ID_URN = BootstrapStep.getUpgradeUrn(UPGRADE_ID);
2021

2122
public BackfillIngestionSourceInfoIndicesStep(

datahub-web-react/src/alchemy-components/theme/foundations/colors.ts

+24-21
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,31 @@ const colors = {
22
transparent: 'transparent',
33
current: 'currentColor',
44
white: '#FFFFFF',
5-
black: '#000000',
5+
black: '#000000', // do not use black, use grays 600 for primary text and 1700 for secondary
66

77
gray: {
8-
100: '#EBECF0',
9-
200: '#CFD1DA',
10-
300: '#A9ADBD',
11-
400: '#81879F',
12-
500: '#5B6282', // primary value
13-
600: '#374066',
14-
700: '#2F3657',
15-
800: '#272D48',
16-
900: '#231A58',
17-
1000: '#F1F3FD', // grays 1000-1300 aren't actually gray, should not be used
18-
1100: '#F1FBFE',
19-
1200: '#FBF3EF',
20-
1300: '#F7FBF4',
21-
1400: '#E9EAEE',
22-
1500: '#F9FAFC',
23-
1600: '#F5F6FA',
24-
1700: '#5F6685',
25-
1800: '#8088A3',
8+
0: '#FFFFFF', // white
9+
100: '#EBECF0', // border
10+
200: '#CFD1DA', // should be deprecated
11+
300: '#A9ADBD', // should be deprecated
12+
400: '#81879F', // should be deprecated
13+
500: '#5B6282', // should be deprecated
14+
600: '#374066', // primary text
15+
700: '#2F3657', // should be deprecated
16+
800: '#272D48', // should be deprecated
17+
900: '#231A58', // should be deprecated
18+
1000: '#F1F3FD', // grays violet 0
19+
1100: '#F1FBFE', // blue 0
20+
1200: '#FBF3EF', // red 0
21+
1300: '#F7FBF4', // green 0
22+
1400: '#E9EAEE', // border
23+
1500: '#F9FAFC', // bg surface
24+
1600: '#F5F6FA', // bg of new nav
25+
1700: '#5F6685', // secondary text
26+
1800: '#8088A3', // tertiary text, disabled text, placeholder text, icon
2627
1900: '#A3A7B9',
28+
2000: '#1E2338', // dark bg-suface
29+
2100: '#171B2B', // dark bg
2730
},
2831

2932
violet: {
@@ -32,8 +35,8 @@ const colors = {
3235
200: '#B0A7EA',
3336
300: '#8C7EE0',
3437
400: '#7565DA',
35-
500: '#533FD1', // primary value
36-
600: '#4C39BE',
38+
500: '#533FD1',
39+
600: '#4C39BE', // primary value
3740
700: '#3B2D94',
3841
800: '#2E2373',
3942
900: '#231A58',

datahub-web-react/src/app/ingest/source/IngestedAssets.tsx

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import { Button, Typography } from 'antd';
22
import React, { useState } from 'react';
33
import styled from 'styled-components';
4+
import { Maybe, ExecutionRequestResult } from '@src/types.generated';
45
import { useGetSearchResultsForMultipleQuery } from '../../../graphql/search.generated';
56
import { EmbeddedListSearchModal } from '../../entity/shared/components/styled/search/EmbeddedListSearchModal';
67
import { ANTD_GRAY } from '../../entity/shared/constants';
78
import { UnionType } from '../../search/utils/constants';
89
import { formatNumber } from '../../shared/formatNumber';
910
import { Message } from '../../shared/Message';
1011
import { useEntityRegistry } from '../../useEntityRegistry';
11-
import { extractEntityTypeCountsFromFacets } from './utils';
12+
import { extractEntityTypeCountsFromFacets, getEntitiesIngestedByType, getTotalEntitiesIngested } from './utils';
1213

1314
const HeaderContainer = styled.div`
1415
display: flex;
@@ -51,19 +52,27 @@ const ViewAllButton = styled(Button)`
5152

5253
type Props = {
5354
id: string;
55+
executionResult?: Maybe<Partial<ExecutionRequestResult>>;
5456
};
5557

5658
const ENTITY_FACET_NAME = 'entity';
5759
const TYPE_NAMES_FACET_NAME = 'typeNames';
5860

59-
export default function IngestedAssets({ id }: Props) {
61+
export default function IngestedAssets({ id, executionResult }: Props) {
6062
const entityRegistry = useEntityRegistry();
6163

6264
// First thing to do is to search for all assets with the id as the run id!
6365
const [showAssetSearch, setShowAssetSearch] = useState(false);
6466

67+
// Try getting the counts via the ingestion report.
68+
const totalEntitiesIngested = executionResult && getTotalEntitiesIngested(executionResult);
69+
const entitiesIngestedByTypeFromReport = executionResult && getEntitiesIngestedByType(executionResult);
70+
71+
// Fallback to the search across entities.
72+
// First thing to do is to search for all assets with the id as the run id!
6573
// Execute search
6674
const { data, loading, error } = useGetSearchResultsForMultipleQuery({
75+
skip: totalEntitiesIngested === null || entitiesIngestedByTypeFromReport === null,
6776
variables: {
6877
input: {
6978
query: '*',
@@ -90,11 +99,13 @@ export default function IngestedAssets({ id }: Props) {
9099
const hasSubTypeFacet = (facets || []).findIndex((facet) => facet.field === TYPE_NAMES_FACET_NAME) >= 0;
91100
const subTypeFacets =
92101
(hasSubTypeFacet && facets?.filter((facet) => facet.field === TYPE_NAMES_FACET_NAME)[0]) || undefined;
102+
93103
const countsByEntityType =
94-
(entityTypeFacets && extractEntityTypeCountsFromFacets(entityRegistry, entityTypeFacets, subTypeFacets)) || [];
104+
entitiesIngestedByTypeFromReport ??
105+
(entityTypeFacets ? extractEntityTypeCountsFromFacets(entityRegistry, entityTypeFacets, subTypeFacets) : []);
95106

96107
// The total number of assets ingested
97-
const total = data?.searchAcrossEntities?.total || 0;
108+
const total = totalEntitiesIngested ?? data?.searchAcrossEntities?.total ?? 0;
98109

99110
return (
100111
<>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import { vi, describe, test, expect, beforeEach, afterAll } from 'vitest';
2+
import { getEntitiesIngestedByType } from '../utils';
3+
import { ExecutionRequestResult } from '../../../../types.generated';
4+
5+
// Mock the structuredReport property of ExecutionRequestResult
6+
const mockExecutionRequestResult = (structuredReportData: any): Partial<ExecutionRequestResult> => {
7+
return {
8+
structuredReport: {
9+
serializedValue: JSON.stringify(structuredReportData),
10+
},
11+
} as Partial<ExecutionRequestResult>;
12+
};
13+
14+
describe('getEntitiesIngestedByType', () => {
15+
// Mock for console.error
16+
const originalConsoleError = console.error;
17+
console.error = vi.fn();
18+
19+
beforeEach(() => {
20+
vi.clearAllMocks();
21+
});
22+
23+
afterAll(() => {
24+
console.error = originalConsoleError;
25+
});
26+
27+
test('returns null when structured report is not available', () => {
28+
const result = getEntitiesIngestedByType({} as Partial<ExecutionRequestResult>);
29+
expect(result).toBeNull();
30+
});
31+
32+
test('returns null when an exception occurs during processing', () => {
33+
// Create a malformed structured report to trigger an exception
34+
const malformedReport = {
35+
source: {
36+
report: {
37+
// Missing aspects property to trigger exception
38+
},
39+
},
40+
};
41+
42+
const result = getEntitiesIngestedByType(mockExecutionRequestResult(malformedReport));
43+
expect(result).toBeNull();
44+
});
45+
46+
test('correctly extracts entity counts from structured report', () => {
47+
// Create a structured report based on the example in the comments
48+
const structuredReport = {
49+
source: {
50+
report: {
51+
aspects: {
52+
container: {
53+
containerProperties: 156,
54+
container: 117,
55+
},
56+
dataset: {
57+
status: 1505,
58+
schemaMetadata: 1505,
59+
datasetProperties: 1505,
60+
container: 1505,
61+
operation: 1521,
62+
},
63+
},
64+
},
65+
},
66+
};
67+
68+
const result = getEntitiesIngestedByType(mockExecutionRequestResult(structuredReport));
69+
70+
expect(result).toEqual([
71+
{
72+
count: 156,
73+
displayName: 'container',
74+
},
75+
{
76+
count: 1521,
77+
displayName: 'dataset',
78+
},
79+
]);
80+
});
81+
82+
test('handles empty aspects object', () => {
83+
const structuredReport = {
84+
source: {
85+
report: {
86+
aspects: {},
87+
},
88+
},
89+
};
90+
91+
const result = getEntitiesIngestedByType(mockExecutionRequestResult(structuredReport));
92+
expect(result).toEqual([]);
93+
});
94+
95+
test('handles aspects with non-numeric values', () => {
96+
const structuredReport = {
97+
source: {
98+
report: {
99+
aspects: {
100+
container: {
101+
containerProperties: '156',
102+
container: 117,
103+
},
104+
},
105+
},
106+
},
107+
};
108+
109+
const result = getEntitiesIngestedByType(mockExecutionRequestResult(structuredReport));
110+
expect(result).toEqual([
111+
{
112+
count: 156,
113+
displayName: 'container',
114+
},
115+
]);
116+
});
117+
});

datahub-web-react/src/app/ingest/source/executions/ExecutionRequestDetailsModal.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,9 @@ export const ExecutionDetailsModal = ({ urn, open, onClose }: Props) => {
193193
</StatusSection>
194194
{(status === SUCCESS || status === SUCCEEDED_WITH_WARNINGS) && (
195195
<IngestedAssetsSection>
196-
{data?.executionRequest?.id && <IngestedAssets id={data?.executionRequest?.id} />}
196+
{data?.executionRequest?.id && (
197+
<IngestedAssets executionResult={result} id={data?.executionRequest?.id} />
198+
)}
197199
</IngestedAssetsSection>
198200
)}
199201
<LogsSection>

0 commit comments

Comments
 (0)