import { ApiPayload, ComponentPayload, GetComponentByExternalAliasInput, SdkError, UnLinkComponentInput, } from '@atlassian/forge-graphql-types'; import { ConfigAsCodeRequests } from '../../config-as-code-requests'; import isValidString from '../../helpers/isValidString'; import { EXTERNAL_ALIAS_SOURCE_COMPONENT_PATH_TO_FILE } from './helpers/createOrUpdateComponent/constants'; import { generateExternalIdWithPrefix } from './helpers/createOrUpdateComponent/helpers'; import { CompassRequests } from '../../compass-requests'; import { deleteAliasesByCreateFromYaml } from './helpers/unlinkComponent/externalAliasManager'; declare module '../../config-as-code-requests' { interface ConfigAsCodeRequests { /** * Unlinks a component with data coming from the configuration as code file. * The following are performed: * Remove Data Manager * Remove External Alias * Returns an array of errors or success to the caller. * * **Required Oauth Scopes:** `write:component:compass` */ unlinkComponent( input: UnLinkComponentInput, ): Promise>; } } async function getComponentDetails( requestApi: CompassRequests, cloudId: string, componentPathAliasId: string, componentId?: string, ): Promise<{ success: boolean; componentPayload: ComponentPayload; errors?: Array; }> { let componentResponse: ApiPayload = null; if (isValidString(componentId)) { componentResponse = await requestApi.getComponent({ componentId, }); } if ( !componentResponse || !componentResponse.success || !componentResponse.data ) { const getComponentByExternalAliasInput: GetComponentByExternalAliasInput = { cloudId, externalId: componentPathAliasId, externalSource: EXTERNAL_ALIAS_SOURCE_COMPONENT_PATH_TO_FILE, }; componentResponse = await requestApi.getComponentByExternalAlias( getComponentByExternalAliasInput, ); } if ( componentResponse && componentResponse.success && componentResponse.data?.component ) { const { component } = componentResponse.data; return { success: true, componentPayload: { component }, errors: [], }; } return { success: false, componentPayload: null, errors: componentResponse?.errors ?? [], }; } /** * Unlink a component from the data manager and removes external aliases. * Pivots on the CREATE-FROM_YAML FF, if ON then the component name and path aliases will be deleted (if they exist) * @param input - UnLinkComponentInput. If the component Id isn't defined in the YAML, * the component is fetched using the component path alias. * @returns - { * success: boolean - TRUE, Only if both detach and deleting external aliases are successful else FALSE. * errors: Array - List of SDK errors that occur throughout. * } */ ConfigAsCodeRequests.prototype.unlinkComponent = async function ( input: UnLinkComponentInput, ) { const { cloudId, filePath, componentId, deduplicationId, additionalExternalAliasesToRemove, } = input; const errorsResp: Array = []; let componentResponse: ComponentPayload = null; try { let unlinkComponentId = null; const componentPathAliasId = generateExternalIdWithPrefix( deduplicationId, filePath, ); const { success, componentPayload, errors } = await getComponentDetails( this.requests, cloudId, componentPathAliasId, componentId, ); if (!success || errors.length > 0) { errorsResp.push(...errors); return { errors: errorsResp, success: false, data: null, }; } componentResponse = componentPayload; unlinkComponentId = componentPayload.component.id; const dataManagerDetachResponse = await this.requests.detachDataManager({ componentId: unlinkComponentId, }); if (dataManagerDetachResponse.success) { const deleteAliasesState = await deleteAliasesByCreateFromYaml( this.requests, componentResponse.component, additionalExternalAliasesToRemove, ); if (deleteAliasesState.success) { console.debug(`Component successfully unlinked ${componentId}`); } errorsResp.push(...deleteAliasesState.errors); } else { console.warn( `Data manager not detached and aliases not removed for component ID ${componentId}`, ); errorsResp.push({ message: `Data manager not detached and aliases not removed for component ID ${componentId}`, }); } } catch (e) { console.error(`Error in unlinkComponent for cloudId ${cloudId}`, e); errorsResp.push({ message: e.message }); } return { errors: errorsResp, success: errorsResp.length === 0, data: componentResponse, }; };