import { CompassExternalAliasInput, Component, CreateLinkInput, } from '@atlassian/forge-graphql-types'; import { CompassYaml } from '../../../../types'; import { CompassRequests } from '../../../../compass-requests'; import reportSyncError from '../report-sync-error'; import { InvalidConfigFileError } from '../validate-config-file/models/errors'; import { DEFAULT_COMPONENT_TYPE_ID, DEFAULT_UNNAMED_COMPONENT_NAME, DUPLICATED_NAME_ERROR_MESSAGE, EXTERNAL_ALIAS_SOURCE_COMPONENT_NAME, EXTERNAL_ALIAS_SOURCE_COMPONENT_PATH_TO_FILE, } from './constants'; import { generateExternalIdWithPrefix, isYamlNameValid, updateComponent, } from './helpers'; import { buildComponentTypeFromYaml } from '../componentReferenceHelper'; type CreateActionWithExistingComponentByNameInput = { requestApi: CompassRequests; componentYaml: CompassYaml; deduplicationId?: string; newPath: string; cloudId: string; externalSourceURL?: string; }; type CreateActionForComponentByPathInput = { requestApi: CompassRequests; componentYaml: CompassYaml; deduplicationId?: string; newPath: string; cloudId: string; externalSourceURL?: string; additionalLinks?: CreateLinkInput[]; additionalExternalAliases?: CompassExternalAliasInput[]; }; const createActionWithExistingComponentByName = async ({ requestApi, newPath, deduplicationId, componentYaml, cloudId, externalSourceURL, }: CreateActionWithExistingComponentByNameInput): Promise => { const { name: yamlName, typeId } = componentYaml; const isCustomTypesByNameEnabled = process.env.ENABLE_CUSTOM_TYPES_BY_NAME === 'true'; const convertedTypeId = isCustomTypesByNameEnabled ? await buildComponentTypeFromYaml(cloudId, typeId, requestApi) : typeId || DEFAULT_COMPONENT_TYPE_ID; // fall back on existing logic const createComponentResponse = await requestApi.createComponent({ cloudId, name: yamlName || DEFAULT_UNNAMED_COMPONENT_NAME, typeId: convertedTypeId, externalAlias: { externalId: generateExternalIdWithPrefix(deduplicationId, newPath), externalSource: EXTERNAL_ALIAS_SOURCE_COMPONENT_PATH_TO_FILE, }, options: { createdFromFile: true, }, }); if (!createComponentResponse.data?.component?.id) { throw new Error( `Unable to create new component: ${JSON.stringify( createComponentResponse.errors.toString(), )}`, ); } await reportSyncError( new InvalidConfigFileError([DUPLICATED_NAME_ERROR_MESSAGE]), createComponentResponse.data.component.id, externalSourceURL, requestApi, ); throw new InvalidConfigFileError([DUPLICATED_NAME_ERROR_MESSAGE]); }; const createActionForComponentByPath = async ({ requestApi, newPath, deduplicationId, componentYaml, cloudId, externalSourceURL, additionalLinks, additionalExternalAliases, }: CreateActionForComponentByPathInput): Promise => { const { name: yamlName, typeId } = componentYaml; const isCustomTypesByNameEnabled = process.env.ENABLE_CUSTOM_TYPES_BY_NAME === 'true'; const convertedTypeId = isCustomTypesByNameEnabled ? await buildComponentTypeFromYaml(cloudId, typeId, requestApi) : typeId || DEFAULT_COMPONENT_TYPE_ID; // fall back on existing logic const createComponentResponse = await requestApi.createComponent({ cloudId, name: isYamlNameValid(yamlName) ? yamlName : DEFAULT_UNNAMED_COMPONENT_NAME, typeId: convertedTypeId, externalAlias: { // TODO COMPASS-13240 let the component take in an array of aliases. externalId: generateExternalIdWithPrefix(deduplicationId, newPath), externalSource: EXTERNAL_ALIAS_SOURCE_COMPONENT_PATH_TO_FILE, }, options: { createdFromFile: true, }, }); if (!createComponentResponse.data?.component?.id) { throw new Error( `Unable to create new component: ${createComponentResponse.errors.toString()}`, ); } if (isYamlNameValid(yamlName)) { await requestApi.createExternalAlias({ componentId: createComponentResponse.data?.component?.id, externalAlias: { externalId: generateExternalIdWithPrefix(deduplicationId, yamlName), externalSource: EXTERNAL_ALIAS_SOURCE_COMPONENT_NAME, }, }); } const fullComponentWithAllLinksAndFields = await requestApi.getComponent({ componentId: createComponentResponse.data.component.id, options: { includeLinks: true, includeCustomFields: true, includeCustomFieldOptions: true, }, }); return updateComponent( cloudId, requestApi, fullComponentWithAllLinksAndFields?.data?.component, componentYaml, additionalLinks, additionalExternalAliases, externalSourceURL, ); }; export { createActionForComponentByPath, createActionWithExistingComponentByName, };