@@ -2,10 +2,62 @@ import { getServiceChildLogger } from '@crowd/logging'
22import { IIntegration , PlatformType } from '@crowd/types'
33
44import { QueryExecutor } from '../queryExecutor'
5- import { getMappedRepos } from '../segments'
5+ import { getReposBySegmentGroupedByPlatform } from '../segments'
66
77const log = getServiceChildLogger ( 'db.integrations' )
88
9+ export function normalizeRepoUrl ( url : string ) : string {
10+ try {
11+ const parsed = new URL ( url )
12+
13+ // Normalize protocol to https
14+ parsed . protocol = 'https:'
15+
16+ // Remove www. prefix and lowercase hostname
17+ parsed . hostname = parsed . hostname . replace ( / ^ w w w \. / , '' ) . toLowerCase ( )
18+
19+ // Lowercase path for GitHub/GitLab (case-insensitive platforms)
20+ if ( parsed . hostname === 'github.com' || parsed . hostname === 'gitlab.com' ) {
21+ parsed . pathname = parsed . pathname . toLowerCase ( )
22+ }
23+
24+ // Remove trailing slashes and .git suffix
25+ parsed . pathname = parsed . pathname . replace ( / \/ + $ / , '' ) . replace ( / \. g i t $ / , '' )
26+
27+ // Remove query string and hash
28+ parsed . search = ''
29+ parsed . hash = ''
30+
31+ return parsed . toString ( )
32+ } catch {
33+ return url
34+ }
35+ }
36+
37+ /**
38+ * Extracts a human-readable label from a repository URL.
39+ * For GitHub/GitLab: returns "owner/repo"
40+ * For others: returns the full URL
41+ */
42+ export function extractLabelFromUrl ( url : string ) : string {
43+ try {
44+ const parsed = new URL ( url )
45+ if (
46+ parsed . hostname === 'github.com' ||
47+ parsed . hostname === 'gitlab.com' ||
48+ parsed . hostname . endsWith ( '.gitlab.com' )
49+ ) {
50+ return parsed . pathname
51+ . slice ( 1 )
52+ . replace ( / \. g i t $ / , '' )
53+ . replace ( / \/ + $ / , '' )
54+ }
55+ return url
56+ } catch {
57+ return url
58+ }
59+ }
60+
961/* eslint-disable @typescript-eslint/no-explicit-any */
1062
1163/**
@@ -609,82 +661,17 @@ export async function findRepositoriesForSegment(
609661 qx : QueryExecutor ,
610662 segmentId : string ,
611663) : Promise < Record < string , Array < { url : string ; label : string } > > > {
612- const integrations = await fetchIntegrationsForSegment ( qx , segmentId )
613-
614- // Initialize result with platform arrays
615- const result : Record < string , Array < { url : string ; label : string } > > = {
616- git : [ ] ,
617- github : [ ] ,
618- gitlab : [ ] ,
619- gerrit : [ ] ,
620- }
621-
622- const addToResult = ( platform : PlatformType , fullUrl : string , label : string ) => {
623- const platformKey = platform . toLowerCase ( )
624- if ( ! result [ platformKey ] . some ( ( item ) => item . url === fullUrl ) ) {
625- result [ platformKey ] . push ( { url : fullUrl , label } )
626- }
627- }
628-
629- // Add mapped repositories from public.repositories (GitHub and GitLab platforms)
630- const [ githubMappedRepos , githubNangoMappedRepos , gitlabMappedRepos ] = await Promise . all ( [
631- getMappedRepos ( qx , segmentId , PlatformType . GITHUB ) ,
632- getMappedRepos ( qx , segmentId , PlatformType . GITHUB_NANGO ) ,
633- getMappedRepos ( qx , segmentId , PlatformType . GITLAB ) ,
634- ] )
635-
636- for ( const repo of [ ...githubMappedRepos , ...githubNangoMappedRepos , ...gitlabMappedRepos ] ) {
637- const url = repo . url
638- try {
639- const parsedUrl = new URL ( url )
640- if ( parsedUrl . hostname === 'github.com' ) {
641- const label = parsedUrl . pathname . slice ( 1 ) // removes leading '/'
642- addToResult ( PlatformType . GITHUB , url , label )
643- }
644- if ( parsedUrl . hostname === 'gitlab.com' ) {
645- const label = parsedUrl . pathname . slice ( 1 ) // removes leading '/'
646- addToResult ( PlatformType . GITLAB , url , label )
647- }
648- } catch ( err ) {
649- log . error ( { err, repo } , 'Error parsing URL for repository!' )
650- }
651- }
652-
653- for ( const i of integrations ) {
654- if ( i . platform === PlatformType . GIT ) {
655- for ( const r of ( i . settings as any ) . remotes ) {
656- try {
657- const url = new URL ( r )
658- let label = r
659-
660- if ( url . hostname === 'gitlab.com' ) {
661- label = url . pathname . slice ( 1 )
662- } else if ( url . hostname === 'github.com' ) {
663- label = url . pathname . slice ( 1 )
664- }
665-
666- addToResult ( i . platform , r , label )
667- } catch {
668- // Invalid URL, skip
669- }
670- }
671- }
664+ // Get all repos grouped by platform (github-nango merged into github)
665+ const reposByPlatform = await getReposBySegmentGroupedByPlatform ( qx , segmentId , true )
672666
673- if ( i . platform === PlatformType . GITLAB ) {
674- for ( const group of Object . values ( ( i . settings as any ) . groupProjects ) as any [ ] ) {
675- for ( const r of group ) {
676- const label = r . path_with_namespace
677- const fullUrl = `https://gitlab.com/${ label } `
678- addToResult ( i . platform , fullUrl , label )
679- }
680- }
681- }
667+ // Transform to include normalized URLs and labels
668+ const result : Record < string , Array < { url : string ; label : string } > > = { }
682669
683- if ( i . platform === PlatformType . GERRIT ) {
684- for ( const r of ( i . settings as any ) . remote . repoNames ) {
685- addToResult ( i . platform , ` ${ ( i . settings as any ) . remote . orgURL } /q/project: ${ r } ` , r )
686- }
687- }
670+ for ( const [ platform , urls ] of Object . entries ( reposByPlatform ) ) {
671+ result [ platform ] = urls . map ( ( url ) => ( {
672+ url : normalizeRepoUrl ( url ) ,
673+ label : extractLabelFromUrl ( url ) ,
674+ } ) )
688675 }
689676
690677 return result
0 commit comments