@@ -23,7 +23,11 @@ import {
2323 updateCollection ,
2424 updateInsightsProject ,
2525} from '@crowd/data-access-layer/src/collections'
26- import { fetchIntegrationsForSegment } from '@crowd/data-access-layer/src/integrations'
26+ import {
27+ fetchIntegrationById ,
28+ fetchIntegrationsForSegment ,
29+ removePlainGitHubRepoMapping ,
30+ } from '@crowd/data-access-layer/src/integrations'
2731import { OrganizationField , findOrgById , queryOrgs } from '@crowd/data-access-layer/src/orgs'
2832import { QueryFilter } from '@crowd/data-access-layer/src/query'
2933import { findSegmentById } from '@crowd/data-access-layer/src/segments'
@@ -426,7 +430,7 @@ export class CollectionService extends LoggerBase {
426430 }
427431
428432 // Add mapped repositories to GitHub platform
429- const segmentRepository = new SegmentRepository ( this . options )
433+ const segmentRepository = new SegmentRepository ( { ... this . options , transaction : tx } )
430434 const githubMappedRepos = await segmentRepository . getGithubMappedRepos ( segmentId )
431435 const gitlabMappedRepos = await segmentRepository . getGitlabMappedRepos ( segmentId )
432436
@@ -634,4 +638,74 @@ export class CollectionService extends LoggerBase {
634638
635639 return result
636640 }
641+
642+ static extractGithubRepoSlug ( url : string ) : any {
643+ const parsedUrl = new URL ( url )
644+ const pathname = parsedUrl . pathname
645+ const parts = pathname . split ( '/' ) . filter ( Boolean )
646+
647+ if ( parts . length >= 2 ) {
648+ return `${ parts [ 0 ] } /${ parts [ 1 ] } `
649+ }
650+
651+ throw new Error ( 'Invalid GitHub URL format' )
652+ }
653+
654+ async findNangoRepositoriesToBeRemoved ( integrationId : string ) : Promise < string [ ] > {
655+ return SequelizeRepository . withTx ( this . options , async ( tx ) => {
656+ const qx = SequelizeRepository . getQueryExecutor ( { ...this . options , transaction : tx } )
657+ const integration = await fetchIntegrationById ( qx , integrationId )
658+
659+ if ( ! integration || integration . platform !== PlatformType . GITHUB_NANGO ) {
660+ return [ ]
661+ }
662+
663+ const repoSlugs = new Set < string > ( )
664+ const settings = integration . settings as any
665+ const reposToBeRemoved = [ ]
666+
667+ if ( ! settings . nangoMapping ) {
668+ return [ ]
669+ }
670+
671+ if ( settings . orgs ) {
672+ for ( const org of settings . orgs ) {
673+ for ( const repo of org . repos ?? [ ] ) {
674+ repoSlugs . add ( CollectionService . extractGithubRepoSlug ( repo . url ) )
675+ }
676+ }
677+ }
678+
679+ if ( settings . repos ) {
680+ for ( const repo of settings . repos ) {
681+ repoSlugs . add ( CollectionService . extractGithubRepoSlug ( repo . url ) )
682+ }
683+ }
684+ // determine which connections to delete if needed
685+ for ( const mappedRepo of Object . values ( settings . nangoMapping ) as {
686+ owner : string
687+ repoName : string
688+ } [ ] ) {
689+ if ( ! repoSlugs . has ( `${ mappedRepo . owner } /${ mappedRepo . repoName } ` ) ) {
690+ reposToBeRemoved . push ( `https://github.com/${ mappedRepo . owner } /${ mappedRepo . repoName } ` )
691+ }
692+ }
693+
694+ return reposToBeRemoved
695+ } )
696+ }
697+
698+ async unmapGithubRepo ( integrationId : string , repo : string ) : Promise < void > {
699+ return SequelizeRepository . withTx ( this . options , async ( tx ) => {
700+ const qx = SequelizeRepository . getQueryExecutor ( { ...this . options , transaction : tx } )
701+ await removePlainGitHubRepoMapping ( qx , this . options . redis , integrationId , repo )
702+ } )
703+ }
704+
705+ async unmapGitlabRepo ( integrationId : string , repo : string ) : Promise < void > {
706+ return SequelizeRepository . withTx ( this . options , async ( tx ) => {
707+ const qx = SequelizeRepository . getQueryExecutor ( { ...this . options , transaction : tx } )
708+ await removePlainGitHubRepoMapping ( qx , this . options . redis , integrationId , repo )
709+ } )
710+ }
637711}
0 commit comments