Skip to content

Commit 600e463

Browse files
authored
feat(ingest/ui): Updated lookml recipe and minor ui enhancements (#15086)
1 parent 2f31635 commit 600e463

File tree

8 files changed

+792
-48
lines changed

8 files changed

+792
-48
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
import { render, screen } from '@testing-library/react';
2+
import { Form } from 'antd';
3+
import React from 'react';
4+
5+
import { FieldType, GIT_INFO_REPO } from '@app/ingestV2/source/builder/RecipeForm/common';
6+
7+
// Mock FormField component for testing
8+
const MockFormField = ({ field, removeMargin: _removeMargin }: { field: any; removeMargin: boolean }) => {
9+
const { name, label, tooltip, type, placeholder, rules, required } = field;
10+
11+
return (
12+
<div data-testid={`form-field-${name}`}>
13+
<label htmlFor={`input-${name}`}>{label}</label>
14+
{tooltip && (
15+
<div data-testid={`tooltip-${name}`}>{typeof tooltip === 'string' ? tooltip : 'React tooltip'}</div>
16+
)}
17+
<input
18+
id={`input-${name}`}
19+
type={type === FieldType.SECRET ? 'password' : 'text'}
20+
placeholder={placeholder}
21+
data-required={required}
22+
data-rules={rules ? rules.length : 0}
23+
/>
24+
</div>
25+
);
26+
};
27+
28+
describe('Common Git Info Fields', () => {
29+
describe('GIT_INFO_REPO', () => {
30+
it('should have correct field properties', () => {
31+
expect(GIT_INFO_REPO.name).toBe('git_info.repo');
32+
expect(GIT_INFO_REPO.label).toBe('Git Repository');
33+
expect(GIT_INFO_REPO.type).toBe(FieldType.TEXT);
34+
expect(GIT_INFO_REPO.fieldPath).toBe('source.config.git_info.repo');
35+
expect(GIT_INFO_REPO.rules).toBeNull();
36+
});
37+
38+
it('should not be required by default', () => {
39+
expect(GIT_INFO_REPO.required).toBeUndefined();
40+
});
41+
42+
it('should render tooltip with multi-platform examples', () => {
43+
render(
44+
<Form>
45+
<MockFormField field={GIT_INFO_REPO} removeMargin={false} />,
46+
</Form>,
47+
);
48+
49+
const tooltip = screen.getByTestId('tooltip-git_info.repo');
50+
expect(tooltip.textContent).toContain('React tooltip');
51+
});
52+
53+
it('should have updated from deprecated github_info', () => {
54+
expect(GIT_INFO_REPO.name).not.toContain('github_info');
55+
expect(GIT_INFO_REPO.name).toContain('git_info');
56+
expect(GIT_INFO_REPO.label).not.toBe('GitHub Repo');
57+
expect(GIT_INFO_REPO.label).toBe('Git Repository');
58+
});
59+
60+
it('should support multiple Git platforms in tooltip', () => {
61+
// Test that the tooltip contains information about multiple platforms
62+
const { tooltip } = GIT_INFO_REPO;
63+
expect(tooltip).toBeDefined();
64+
65+
// Since tooltip is a React component, we test its structure
66+
expect(React.isValidElement(tooltip)).toBe(true);
67+
});
68+
});
69+
70+
describe('Field Configuration', () => {
71+
it('should have correct field path structure', () => {
72+
expect(GIT_INFO_REPO.fieldPath).toBe('source.config.git_info.repo');
73+
expect(GIT_INFO_REPO.fieldPath).toMatch(/^source\.config\.git_info\./);
74+
});
75+
76+
it('should be a text input field', () => {
77+
expect(GIT_INFO_REPO.type).toBe(FieldType.TEXT);
78+
});
79+
80+
it('should not have validation rules', () => {
81+
expect(GIT_INFO_REPO.rules).toBeNull();
82+
});
83+
});
84+
85+
describe('Multi-Platform Support', () => {
86+
it('should have tooltip that mentions multiple platforms', () => {
87+
// The tooltip should be a React component that includes examples
88+
// for different Git platforms
89+
expect(GIT_INFO_REPO.tooltip).toBeDefined();
90+
expect(React.isValidElement(GIT_INFO_REPO.tooltip)).toBe(true);
91+
});
92+
93+
it('should support flexible repository URL formats', () => {
94+
// The field should accept various repository URL formats
95+
// This is tested by the fact that there are no strict validation rules
96+
expect(GIT_INFO_REPO.rules).toBeNull();
97+
});
98+
});
99+
100+
describe('Backward Compatibility', () => {
101+
it('should replace deprecated github_info field', () => {
102+
// Ensure the field name has been updated from github_info to git_info
103+
expect(GIT_INFO_REPO.name).toBe('git_info.repo');
104+
expect(GIT_INFO_REPO.name).not.toBe('github_info.repo');
105+
});
106+
107+
it('should have updated label from GitHub-specific to generic', () => {
108+
expect(GIT_INFO_REPO.label).toBe('Git Repository');
109+
expect(GIT_INFO_REPO.label).not.toBe('GitHub Repo');
110+
});
111+
112+
it('should have updated field path', () => {
113+
expect(GIT_INFO_REPO.fieldPath).toBe('source.config.git_info.repo');
114+
expect(GIT_INFO_REPO.fieldPath).not.toBe('source.config.github_info.repo');
115+
});
116+
});
117+
});
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import { FieldType, GIT_INFO_REPO } from '@app/ingestV2/source/builder/RecipeForm/common';
2+
import { RECIPE_FIELDS } from '@app/ingestV2/source/builder/RecipeForm/constants';
3+
import { LOOKML, LOOKML_GIT_INFO_REPO } from '@app/ingestV2/source/builder/RecipeForm/lookml';
4+
5+
describe('Constants Git Info Integration', () => {
6+
describe('Field Imports', () => {
7+
it('should import LOOKML_GIT_INFO_REPO from lookml module', () => {
8+
expect(LOOKML_GIT_INFO_REPO).toBeDefined();
9+
expect(LOOKML_GIT_INFO_REPO.name).toBe('git_info.repo');
10+
});
11+
12+
it('should import GIT_INFO_REPO from common module', () => {
13+
expect(GIT_INFO_REPO).toBeDefined();
14+
expect(GIT_INFO_REPO.name).toBe('git_info.repo');
15+
});
16+
});
17+
18+
describe('Source Configuration Integration', () => {
19+
it('should include LOOKML_GIT_INFO_REPO in LOOKML source config', () => {
20+
const lookmlConfig = RECIPE_FIELDS[LOOKML];
21+
expect(lookmlConfig).toBeDefined();
22+
expect(lookmlConfig.fields).toContain(LOOKML_GIT_INFO_REPO);
23+
});
24+
25+
it('should have correct field order in LOOKML config', () => {
26+
const lookmlConfig = RECIPE_FIELDS[LOOKML];
27+
const { fields } = lookmlConfig;
28+
29+
// LOOKML_GIT_INFO_REPO should be the first field
30+
expect(fields[0]).toBe(LOOKML_GIT_INFO_REPO);
31+
});
32+
33+
it('should not contain deprecated github_info references', () => {
34+
const lookmlConfig = RECIPE_FIELDS[LOOKML];
35+
const { fields } = lookmlConfig;
36+
37+
// Check that no fields have github_info in their name
38+
const githubInfoFields = fields.filter((field) => field.name && field.name.includes('github_info'));
39+
expect(githubInfoFields).toHaveLength(0);
40+
});
41+
42+
it('should contain git_info references', () => {
43+
const lookmlConfig = RECIPE_FIELDS[LOOKML];
44+
const { fields } = lookmlConfig;
45+
46+
// Check that fields have git_info in their name
47+
const gitInfoFields = fields.filter((field) => field.name && field.name.includes('git_info'));
48+
expect(gitInfoFields.length).toBeGreaterThan(0);
49+
});
50+
});
51+
52+
describe('Field Consistency', () => {
53+
it('should have consistent field paths for git_info', () => {
54+
const lookmlConfig = RECIPE_FIELDS[LOOKML];
55+
const { fields } = lookmlConfig;
56+
57+
const gitInfoFields = fields.filter((field) => field.name && field.name.includes('git_info'));
58+
59+
gitInfoFields.forEach((field) => {
60+
expect(field.fieldPath).toMatch(/^source\.config\.git_info\./);
61+
});
62+
});
63+
64+
it('should have proper field types for git_info fields', () => {
65+
const lookmlConfig = RECIPE_FIELDS[LOOKML];
66+
const { fields } = lookmlConfig;
67+
68+
const gitInfoFields = fields.filter((field) => field.name && field.name.includes('git_info'));
69+
70+
gitInfoFields.forEach((field) => {
71+
expect(field.type).toBeDefined();
72+
expect([FieldType.TEXT, FieldType.SECRET]).toContain(field.type);
73+
});
74+
});
75+
});
76+
77+
describe('Migration from github_info', () => {
78+
it('should not have any github_info field references', () => {
79+
const lookmlConfig = RECIPE_FIELDS[LOOKML];
80+
const { fields } = lookmlConfig;
81+
82+
// Ensure no fields reference the old github_info structure
83+
const oldFieldPaths = fields.filter((field) => field.fieldPath && field.fieldPath.includes('github_info'));
84+
expect(oldFieldPaths).toHaveLength(0);
85+
});
86+
87+
it('should have updated field names from github_info to git_info', () => {
88+
const lookmlConfig = RECIPE_FIELDS[LOOKML];
89+
const { fields } = lookmlConfig;
90+
91+
const gitInfoFields = fields.filter((field) => field.name && field.name.includes('git_info'));
92+
93+
expect(gitInfoFields.length).toBeGreaterThan(0);
94+
95+
gitInfoFields.forEach((field) => {
96+
expect(field.name).toMatch(/^git_info\./);
97+
expect(field.name).not.toMatch(/^github_info\./);
98+
});
99+
});
100+
});
101+
102+
describe('Field Validation', () => {
103+
it('should have required fields properly marked', () => {
104+
const lookmlConfig = RECIPE_FIELDS[LOOKML];
105+
const { fields } = lookmlConfig;
106+
107+
const requiredFields = fields.filter((field) => field.required === true);
108+
expect(requiredFields.length).toBeGreaterThan(0);
109+
});
110+
111+
it('should have validation rules for required fields', () => {
112+
const lookmlConfig = RECIPE_FIELDS[LOOKML];
113+
const { fields } = lookmlConfig;
114+
115+
const fieldsWithRules = fields.filter((field) => field.rules && field.rules.length > 0);
116+
117+
expect(fieldsWithRules.length).toBeGreaterThan(0);
118+
});
119+
});
120+
});
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { LOOKML_GIT_INFO_REPO_SSH_LOCATOR } from '@app/ingestV2/source/builder/RecipeForm/lookml';
2+
3+
describe('Git Info Validation Logic', () => {
4+
const createValidator = (repoValue: string | undefined | null) => {
5+
return LOOKML_GIT_INFO_REPO_SSH_LOCATOR.rules![0]({
6+
getFieldValue: (fieldName) => {
7+
if (fieldName === 'git_info.repo') return repoValue;
8+
return undefined;
9+
},
10+
});
11+
};
12+
13+
describe('REPO_SSH_LOCATOR Validation', () => {
14+
describe('GitHub Repository Detection', () => {
15+
it('should not require SSH locator for GitHub short format', async () => {
16+
const validator = createValidator('datahub-project/datahub');
17+
await expect(validator.validator({}, '')).resolves.toBeUndefined();
18+
});
19+
20+
it('should not require SSH locator for GitHub full URL', async () => {
21+
const validator = createValidator('https://github.com/datahub-project/datahub');
22+
await expect(validator.validator({}, '')).resolves.toBeUndefined();
23+
});
24+
25+
it('should not require SSH locator for GitHub URL without protocol', async () => {
26+
const validator = createValidator('github.com/datahub-project/datahub');
27+
await expect(validator.validator({}, '')).resolves.toBeUndefined();
28+
});
29+
30+
it('should not require SSH locator for GitHub URL with trailing slash', async () => {
31+
const validator = createValidator('https://github.com/datahub-project/datahub/');
32+
await expect(validator.validator({}, '')).resolves.toBeUndefined();
33+
});
34+
});
35+
36+
describe('GitLab Repository Detection', () => {
37+
it('should not require SSH locator for GitLab full URL', async () => {
38+
const validator = createValidator('https://gitlab.com/gitlab-org/gitlab');
39+
await expect(validator.validator({}, '')).resolves.toBeUndefined();
40+
});
41+
42+
it('should not require SSH locator for GitLab URL without protocol', async () => {
43+
const validator = createValidator('gitlab.com/gitlab-org/gitlab');
44+
await expect(validator.validator({}, '')).resolves.toBeUndefined();
45+
});
46+
47+
it('should not require SSH locator for GitLab URL with trailing slash', async () => {
48+
const validator = createValidator('https://gitlab.com/gitlab-org/gitlab/');
49+
await expect(validator.validator({}, '')).resolves.toBeUndefined();
50+
});
51+
});
52+
53+
describe('Other Git Platforms', () => {
54+
it('should require SSH locator for Bitbucket', async () => {
55+
const validator = createValidator('https://bitbucket.org/org/repo');
56+
await expect(validator.validator({}, '')).rejects.toThrow(
57+
'Repository SSH Locator is required for Git platforms other than GitHub and GitLab',
58+
);
59+
});
60+
61+
it('should require SSH locator for custom Git server', async () => {
62+
const validator = createValidator('https://custom-git.com/org/repo');
63+
await expect(validator.validator({}, '')).rejects.toThrow(
64+
'Repository SSH Locator is required for Git platforms other than GitHub and GitLab',
65+
);
66+
});
67+
68+
it('should require SSH locator for SSH URL format', async () => {
69+
const validator = createValidator('git@custom-server.com:org/repo');
70+
await expect(validator.validator({}, '')).rejects.toThrow(
71+
'Repository SSH Locator is required for Git platforms other than GitHub and GitLab',
72+
);
73+
});
74+
75+
it('should not require SSH locator when SSH locator is provided', async () => {
76+
const validator = createValidator('https://custom-git.com/org/repo');
77+
await expect(validator.validator({}, 'git@custom-git.com:org/repo.git')).resolves.toBeUndefined();
78+
});
79+
});
80+
81+
describe('Edge Cases', () => {
82+
it('should not require SSH locator when repo is undefined', async () => {
83+
const validator = createValidator(undefined);
84+
await expect(validator.validator({}, '')).resolves.toBeUndefined();
85+
});
86+
87+
it('should not require SSH locator when repo is null', async () => {
88+
const validator = createValidator(null);
89+
await expect(validator.validator({}, '')).resolves.toBeUndefined();
90+
});
91+
92+
it('should not require SSH locator when repo is empty string', async () => {
93+
const validator = createValidator('');
94+
await expect(validator.validator({}, '')).resolves.toBeUndefined();
95+
});
96+
97+
it('should handle case-insensitive GitHub detection', async () => {
98+
const validator = createValidator('https://GITHUB.COM/datahub-project/datahub');
99+
await expect(validator.validator({}, '')).resolves.toBeUndefined();
100+
});
101+
102+
it('should handle case-insensitive GitLab detection', async () => {
103+
const validator = createValidator('https://GITLAB.COM/gitlab-org/gitlab');
104+
await expect(validator.validator({}, '')).resolves.toBeUndefined();
105+
});
106+
});
107+
108+
describe('Complex Repository URLs', () => {
109+
it('should handle GitHub URLs with additional path segments', async () => {
110+
const validator = createValidator('https://github.com/datahub-project/datahub/tree/main/src');
111+
await expect(validator.validator({}, '')).resolves.toBeUndefined();
112+
});
113+
114+
it('should handle GitLab URLs with additional path segments', async () => {
115+
const validator = createValidator('https://gitlab.com/gitlab-org/gitlab/-/tree/main/src');
116+
await expect(validator.validator({}, '')).resolves.toBeUndefined();
117+
});
118+
119+
it('should require SSH locator for non-GitHub/GitLab URLs with similar patterns', async () => {
120+
const validator = createValidator('https://github-enterprise.company.com/org/repo');
121+
await expect(validator.validator({}, '')).rejects.toThrow(
122+
'Repository SSH Locator is required for Git platforms other than GitHub and GitLab',
123+
);
124+
});
125+
});
126+
});
127+
128+
describe('Validation Error Messages', () => {
129+
it('should provide clear error message for missing SSH locator', async () => {
130+
const validator = createValidator('https://custom-git.com/org/repo');
131+
try {
132+
await validator.validator({}, '');
133+
} catch (error: any) {
134+
expect(error.message).toBe(
135+
'Repository SSH Locator is required for Git platforms other than GitHub and GitLab',
136+
);
137+
}
138+
});
139+
});
140+
});

0 commit comments

Comments
 (0)