diff --git a/src/components/ImportForm/ComponentSection/GitOptions.tsx b/src/components/ImportForm/ComponentSection/GitOptions.tsx index 33730fb..7174266 100644 --- a/src/components/ImportForm/ComponentSection/GitOptions.tsx +++ b/src/components/ImportForm/ComponentSection/GitOptions.tsx @@ -2,12 +2,24 @@ import * as React from 'react'; import { ExpandableSection, FormSection, PageSection } from '@patternfly/react-core'; import { InputField } from 'formik-pf'; import HelpPopover from '../../HelpPopover'; +import { GitProviderDropdown } from './GitProviderDropdown'; -const GitOptions: React.FC> = () => { +type GitOptionProps = { + isGitAdvancedOpen: boolean; + setGitAdvancedOpen: (x) => void; +}; + +const GitOptions: React.FC> = ({ + isGitAdvancedOpen, + setGitAdvancedOpen, +}) => { return ( setGitAdvancedOpen((x) => !x)} > @@ -27,6 +39,12 @@ const GitOptions: React.FC> = () => { } /> + + diff --git a/src/components/ImportForm/ComponentSection/GitProviderDropdown.tsx b/src/components/ImportForm/ComponentSection/GitProviderDropdown.tsx new file mode 100644 index 0000000..53d85da --- /dev/null +++ b/src/components/ImportForm/ComponentSection/GitProviderDropdown.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { useField } from 'formik'; +import DropdownField from '../../../shared/components/formik-fields/DropdownField'; +import { GIT_PROVIDER_ANNOTATION_VALUE } from '../../../utils/component-utils'; + +type GitProviderDropdownProps = Omit< + React.ComponentProps, + 'items' | 'label' | 'placeholder' +>; + +export const GitProviderDropdown: React.FC> = ( + props, +) => { + const [{ value }, , { setValue }] = useField(props.name); + + const dropdownItems = [ + { key: GIT_PROVIDER_ANNOTATION_VALUE.GITHUB, value: GIT_PROVIDER_ANNOTATION_VALUE.GITHUB }, + { key: GIT_PROVIDER_ANNOTATION_VALUE.GITLAB, value: GIT_PROVIDER_ANNOTATION_VALUE.GITLAB }, + { key: GIT_PROVIDER_ANNOTATION_VALUE.OTHERS, value: GIT_PROVIDER_ANNOTATION_VALUE.OTHERS }, + ]; + + return ( +
+ setValue(provider)} + /> +
+ ); +}; diff --git a/src/components/ImportForm/ComponentSection/SourceSection.tsx b/src/components/ImportForm/ComponentSection/SourceSection.tsx index 0425655..82d8cc0 100644 --- a/src/components/ImportForm/ComponentSection/SourceSection.tsx +++ b/src/components/ImportForm/ComponentSection/SourceSection.tsx @@ -3,11 +3,14 @@ import { ValidatedOptions } from '@patternfly/react-core'; import { useField, useFormikContext } from 'formik'; import { InputField, SwitchField } from 'formik-pf'; import GitUrlParse from 'git-url-parse'; +import { detectGitType, GitProvider } from '../../../shared/utils/git-utils'; +import { GIT_PROVIDER_ANNOTATION_VALUE } from '../../../utils/component-utils'; import { ImportFormValues } from '../type'; import GitOptions from './GitOptions'; export const SourceSection = () => { const [, { touched, error }] = useField('source.git.url'); + const [isGitAdvancedOpen, setGitAdvancedOpen] = React.useState(false); const { touched: touchedValues, setFieldValue } = useFormikContext(); const validated = touched ? touched && !error @@ -16,19 +19,40 @@ export const SourceSection = () => { : ValidatedOptions.default; const handleChange = React.useCallback( - (event) => { - if (validated && !touchedValues.componentName) { + async (event) => { + if (validated) { + const gitType = detectGitType(event.target?.value as string); + if (gitType !== GitProvider.GITHUB && gitType !== GitProvider.GITLAB) { + await setFieldValue('gitProviderAnnotation', ''); + setGitAdvancedOpen(true); + } + if (gitType === GitProvider.GITHUB) { + await setFieldValue('gitProviderAnnotation', GIT_PROVIDER_ANNOTATION_VALUE.GITHUB); + setGitAdvancedOpen(false); + } + if (gitType === GitProvider.GITLAB) { + await setFieldValue('gitProviderAnnotation', GIT_PROVIDER_ANNOTATION_VALUE.GITLAB); + setGitAdvancedOpen(false); + } + + let parsed: GitUrlParse.GitUrl; let name: string; try { - name = GitUrlParse(event.target?.value ?? '').name; + parsed = GitUrlParse(event.target?.value ?? ''); + await setFieldValue('gitURLAnnotation', parsed?.resource); + name = parsed.name; } catch { name = ''; + await setFieldValue('gitURLAnnotation', ''); + } + if (!touchedValues.componentName) { + await setFieldValue('componentName', name); } - void setFieldValue('componentName', name); } }, [setFieldValue, touchedValues.componentName, validated], ); + return ( <> { placeholder="Enter your source" validated={validated} isRequired - data-test="enter-source" + data-testid="enter-source" onChange={handleChange} /> {validated === ValidatedOptions.success ? ( ) : null} - {validated === ValidatedOptions.success ? : null} + {validated === ValidatedOptions.success ? ( + + ) : null} ); }; diff --git a/src/components/ImportForm/ComponentSection/__tests__/ComponentSection.spec.tsx b/src/components/ImportForm/ComponentSection/__tests__/ComponentSection.spec.tsx index fe057b9..ad0cc5e 100644 --- a/src/components/ImportForm/ComponentSection/__tests__/ComponentSection.spec.tsx +++ b/src/components/ImportForm/ComponentSection/__tests__/ComponentSection.spec.tsx @@ -1,9 +1,11 @@ -import { screen, waitFor } from '@testing-library/react'; +import { screen, waitFor, configure } from '@testing-library/react'; import { userEvent } from '@testing-library/user-event'; import { formikRenderer } from '../../../../utils/test-utils'; import { ComponentSection } from '../ComponentSection'; import '@testing-library/jest-dom'; +configure({ testIdAttribute: 'data-test' }); + describe('ComponentSection', () => { it('should render component section', () => { formikRenderer(, { source: { git: { url: '' } } }); @@ -22,19 +24,43 @@ describe('ComponentSection', () => { await user.tab(); await waitFor(() => screen.getByText('Show advanced Git options')); }); - it('should get private image repo switch when git src is ready', async () => { + + it('should expand git options if source url is others', async () => { formikRenderer(, { source: { git: { url: '' } }, }); const user = userEvent.setup(); const source = screen.getByPlaceholderText('Enter your source'); - await user.type(source, 'https://github.com/abcd/repo.git'); + await user.type(source, 'https://bitbucket.com/abcd/repo.git'); + await user.tab(); + await waitFor(() => screen.getByText('Hide advanced Git options')); + }); + + it('should show advanced Annotation section', async () => { + formikRenderer(, { + source: { git: { url: '' } }, + }); + const user = userEvent.setup(); + const source = screen.getByPlaceholderText('Enter your source'); + + await user.type(source, 'https://bitbucket.com/abcd/repo.git'); await user.tab(); + await waitFor(() => screen.getByTestId('url-annotation')); + }); + + it('should populate annotation fields', async () => { + formikRenderer(, { + source: { git: { url: '' } }, + }); + const user = userEvent.setup(); + const source = screen.getByPlaceholderText('Enter your source'); - const switchCheckbox = screen.getByLabelText('Should the image produced be private?'); - expect(switchCheckbox).not.toBeChecked(); - await user.click(switchCheckbox); - expect(switchCheckbox).toBeChecked(); + await user.type(source, 'https://gitlab.com/abcd/repo.git'); + await user.tab(); + await waitFor(() => + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + expect((screen.getByTestId('url-annotation') as HTMLInputElement).value).toBe('gitlab.com'), + ); }); }); diff --git a/src/components/ImportForm/GitImportForm.tsx b/src/components/ImportForm/GitImportForm.tsx index afb78cf..8c461ab 100644 --- a/src/components/ImportForm/GitImportForm.tsx +++ b/src/components/ImportForm/GitImportForm.tsx @@ -26,6 +26,8 @@ export const GitImportForm: React.FC<{ applicationName: string }> = ({ applicati inAppContext: !!applicationName, showComponent: !!applicationName, componentName: '', + gitProviderAnnotation: '', + gitURLAnnotation: '', isPrivateRepo: false, source: { git: { diff --git a/src/components/ImportForm/submit-utils.ts b/src/components/ImportForm/submit-utils.ts index a1f50b5..3648e4f 100644 --- a/src/components/ImportForm/submit-utils.ts +++ b/src/components/ImportForm/submit-utils.ts @@ -40,6 +40,8 @@ export const createResources = async ( source, application, componentName, + gitProviderAnnotation, + gitURLAnnotation, inAppContext, importSecrets = [], pipeline, @@ -66,7 +68,7 @@ export const createResources = async ( } if (showComponent) { await createComponent( - { componentName, application, source }, + { componentName, application, source, gitProviderAnnotation, gitURLAnnotation }, applicationName, namespace, workspace, @@ -102,7 +104,7 @@ export const createResources = async ( await createSecrets(importSecrets, workspace, namespace, true); createdComponent = await createComponent( - { componentName, application, source }, + { componentName, application, gitProviderAnnotation, source, gitURLAnnotation }, applicationName, namespace, workspace, diff --git a/src/components/ImportForm/type.ts b/src/components/ImportForm/type.ts index 795839c..9161c95 100644 --- a/src/components/ImportForm/type.ts +++ b/src/components/ImportForm/type.ts @@ -5,6 +5,8 @@ export type ImportFormValues = { inAppContext: boolean; showComponent: boolean; componentName: string; + gitProviderAnnotation?: string; + gitURLAnnotation?: string; isPrivateRepo: boolean; source: { git: { diff --git a/src/types/component.ts b/src/types/component.ts index 993b2e1..85e4f87 100644 --- a/src/types/component.ts +++ b/src/types/component.ts @@ -29,6 +29,8 @@ export enum NudgeStats { export type ComponentSpecs = { componentName: string; + gitProviderAnnotation?: string; + gitURLAnnotation?: string; application: string; secret?: string; source?: ComponentSource; diff --git a/src/utils/component-utils.ts b/src/utils/component-utils.ts index a871ca7..ebdb8ad 100644 --- a/src/utils/component-utils.ts +++ b/src/utils/component-utils.ts @@ -14,6 +14,14 @@ export const BUILD_REQUEST_ANNOTATION = 'build.appstudio.openshift.io/request'; export const BUILD_STATUS_ANNOTATION = 'build.appstudio.openshift.io/status'; +export const GIT_PROVIDER_ANNOTATION = 'git-provider'; +export const GIT_PROVIDER_ANNOTATION_VALUE = { + GITHUB: 'github', + GITLAB: 'gitlab', + OTHERS: 'others', +}; +export const GITLAB_PROVIDER_URL_ANNOTATION = 'git-provider-url'; + export enum ComponentBuildState { enabled = 'enabled', disabled = 'disabled', diff --git a/src/utils/create-utils.ts b/src/utils/create-utils.ts index 6b1ecd1..daa93b4 100644 --- a/src/utils/create-utils.ts +++ b/src/utils/create-utils.ts @@ -33,7 +33,12 @@ import { ImageRepositoryVisibility, } from '../types'; import { ComponentSpecs } from './../types/component'; -import { BUILD_REQUEST_ANNOTATION, BuildRequest } from './component-utils'; +import { + BuildRequest, + BUILD_REQUEST_ANNOTATION, + GIT_PROVIDER_ANNOTATION, + GITLAB_PROVIDER_URL_ANNOTATION, +} from './component-utils'; export const sanitizeName = (name: string) => name.split(/ |\./).join('-').toLowerCase(); @@ -104,7 +109,17 @@ export const createComponent = ( enablePac: boolean = true, annotations?: { [key: string]: string }, ) => { - const { componentName, containerImage, source, replicas, resources, env, targetPort } = component; + const { + componentName, + gitProviderAnnotation, + gitURLAnnotation, + containerImage, + source, + replicas, + resources, + env, + targetPort, + } = component; const name = component.componentName.split(/ |\./).join('-').toLowerCase(); @@ -140,8 +155,14 @@ export const createComponent = ( verb === 'update' ? { ...originalComponent, spec: newComponent.spec } : newComponent; // merge additional annotations - if (annotations) { - resource.metadata.annotations = { ...resource.metadata.annotations, ...annotations }; + if (annotations || gitProviderAnnotation || gitURLAnnotation) { + // Add gitlab annotaions in case of gitlab repo + const newAnnotations = annotations; + if (gitProviderAnnotation || gitURLAnnotation) { + newAnnotations[GIT_PROVIDER_ANNOTATION] = gitProviderAnnotation; + newAnnotations[GITLAB_PROVIDER_URL_ANNOTATION] = gitURLAnnotation; + } + resource.metadata.annotations = { ...resource.metadata.annotations, ...newAnnotations }; } return verb === 'create'