@@ -15,6 +15,7 @@ import { BitbucketConnectionConfig, GerritConnectionConfig, GiteaConnectionConfi
1515import { ProjectVisibility } from "azure-devops-node-api/interfaces/CoreInterfaces.js" ;
1616import path from 'path' ;
1717import fs from 'fs/promises' ;
18+ import { fileURLToPath } from 'node:url' ;
1819import { glob } from 'glob' ;
1920import { getLocalDefaultBranch , getOriginUrl , isPathAValidGitRepoRoot , isUrlAValidGitRepo } from './git.js' ;
2021import assert from 'assert' ;
@@ -106,7 +107,7 @@ export const createGitHubRepoRecord = ({
106107 . replace ( / ^ h t t p s ? : \/ \/ / , '' ) ;
107108
108109 const repoDisplayName = repo . full_name ;
109- const repoName = path . join ( repoNameRoot , repoDisplayName ) ;
110+ const repoName = path . posix . join ( repoNameRoot , repoDisplayName ) ;
110111 const cloneUrl = new URL ( repo . clone_url ! ) ;
111112 const isPublic = repo . private === false ;
112113
@@ -184,7 +185,7 @@ export const compileGitlabConfig = async (
184185 project . visibility === 'public' ||
185186 project . visibility === 'internal' ;
186187 const repoDisplayName = project . path_with_namespace ;
187- const repoName = path . join ( repoNameRoot , repoDisplayName ) ;
188+ const repoName = path . posix . join ( repoNameRoot , repoDisplayName ) ;
188189 // project.avatar_url is not directly accessible with tokens; use the avatar API endpoint if available
189190 const avatarUrl = project . avatar_url
190191 ? new URL ( `/api/v4/projects/${ project . id } /avatar` , hostUrl ) . toString ( )
@@ -263,7 +264,7 @@ export const compileGiteaConfig = async (
263264 const cloneUrl = new URL ( repo . clone_url ! ) ;
264265 cloneUrl . host = configUrl . host
265266 const repoDisplayName = repo . full_name ! ;
266- const repoName = path . join ( repoNameRoot , repoDisplayName ) ;
267+ const repoName = path . posix . join ( repoNameRoot , repoDisplayName ) ;
267268 const isPublic = repo . internal === false && repo . private === false ;
268269
269270 logger . debug ( `Found gitea repo ${ repoDisplayName } with webUrl: ${ repo . html_url } ` ) ;
@@ -326,9 +327,9 @@ export const compileGerritConfig = async (
326327 . replace ( / ^ h t t p s ? : \/ \/ / , '' ) ;
327328
328329 const repos = gerritRepos . map ( ( project ) => {
329- const cloneUrl = new URL ( path . join ( hostUrl , encodeURIComponent ( project . name ) ) ) ;
330+ const cloneUrl = new URL ( path . posix . join ( hostUrl , encodeURIComponent ( project . name ) ) ) ;
330331 const repoDisplayName = project . name ;
331- const repoName = path . join ( repoNameRoot , repoDisplayName ) ;
332+ const repoName = path . posix . join ( repoNameRoot , repoDisplayName ) ;
332333
333334 const webUrl = ( ( ) => {
334335 if ( ! project . web_links || project . web_links . length === 0 ) {
@@ -344,7 +345,7 @@ export const compileGerritConfig = async (
344345 // https://github.com/GerritCodeReview/plugins_gitiles/blob/5ee7f57/src/main/java/com/googlesource/gerrit/plugins/gitiles/GitilesWeblinks.java#L50
345346 if ( webUrl . startsWith ( '/plugins/gitiles/' ) ) {
346347 logger . debug ( `WebUrl is a gitiles path, joining with hostUrl: ${ webUrl } ` ) ;
347- return new URL ( path . join ( hostUrl , webUrl ) ) . toString ( ) ;
348+ return new URL ( path . posix . join ( hostUrl , webUrl ) ) . toString ( ) ;
348349 } else {
349350 logger . debug ( `WebUrl is not a gitiles path, returning as is: ${ webUrl } ` ) ;
350351 return webUrl ;
@@ -499,7 +500,7 @@ export const compileBitbucketConfig = async (
499500 : ( repo as BitbucketCloudRepository ) . is_private === false ;
500501 const isArchived = isServer ? ( repo as BitbucketServerRepository ) . archived === true : false ;
501502 const isFork = isServer ? ( repo as BitbucketServerRepository ) . origin !== undefined : ( repo as BitbucketCloudRepository ) . parent !== undefined ;
502- const repoName = path . join ( repoNameRoot , displayName ) ;
503+ const repoName = path . posix . join ( repoNameRoot , displayName ) ;
503504 const cloneUrl = getCloneUrl ( repo ) ;
504505 const webUrl = getWebUrl ( repo ) ;
505506 const defaultBranch = isServer ? ( repo as BitbucketServerRepository ) . defaultBranch : ( repo as BitbucketCloudRepository ) . mainbranch ?. name ;
@@ -590,8 +591,15 @@ export const compileGenericGitHostConfig_file = async (
590591 const configUrl = new URL ( config . url ) ;
591592 assert ( configUrl . protocol === 'file:' , 'config.url must be a file:// URL' ) ;
592593
594+ let folderPath : string ;
595+ try {
596+ folderPath = fileURLToPath ( configUrl ) . replace ( / \\ / g, '/' ) ;
597+ } catch {
598+ folderPath = configUrl . pathname ;
599+ }
600+
593601 // Resolve the glob pattern to a list of repo-paths
594- const repoPaths = await glob ( configUrl . pathname , {
602+ const repoPaths = await glob ( folderPath , {
595603 absolute : true ,
596604 } ) ;
597605
@@ -600,7 +608,7 @@ export const compileGenericGitHostConfig_file = async (
600608
601609 // Warn if the glob pattern matched no paths at all
602610 if ( repoPaths . length === 0 ) {
603- const warning = `No paths matched the pattern '${ configUrl . pathname } '. Please verify the path exists and is accessible.` ;
611+ const warning = `No paths matched the pattern '${ folderPath } '. Please verify the path exists and is accessible.` ;
604612 logger . warn ( warning ) ;
605613 warnings . push ( warning ) ;
606614 return {
@@ -609,7 +617,7 @@ export const compileGenericGitHostConfig_file = async (
609617 } ;
610618 }
611619
612- logger . debug ( `Found ${ repoPaths . length } path(s) matching pattern '${ configUrl . pathname } '` ) ;
620+ logger . debug ( `Found ${ repoPaths . length } path(s) matching pattern '${ folderPath } '` ) ;
613621
614622 await Promise . all ( repoPaths . map ( ( repoPath ) => gitOperationLimit ( async ( ) => {
615623 const stat = await fs . stat ( repoPath ) . catch ( ( ) => null ) ;
@@ -651,7 +659,7 @@ export const compileGenericGitHostConfig_file = async (
651659 const hostWithPort = extractHostWithPort ( origin ) ?? remoteUrl . host ;
652660 // Decode URL-encoded characters (e.g., %20 -> space) to ensure consistent repo names
653661 const decodedPathname = decodeURIComponent ( remoteUrl . pathname ) ;
654- const repoName = path . join ( hostWithPort , decodedPathname . replace ( / \. g i t $ / , '' ) ) ;
662+ const repoName = path . posix . join ( hostWithPort , decodedPathname . replace ( / \. g i t $ / , '' ) ) ;
655663
656664 const repo : RepoData = {
657665 external_codeHostType : 'genericGitHost' ,
@@ -723,7 +731,7 @@ export const compileGenericGitHostConfig_url = async (
723731
724732 // @note : matches the naming here:
725733 // https://github.com/sourcebot-dev/zoekt/blob/main/gitindex/index.go#L293
726- const repoName = path . join ( remoteUrl . host , remoteUrl . pathname . replace ( / \. g i t $ / , '' ) ) ;
734+ const repoName = path . posix . join ( remoteUrl . host , remoteUrl . pathname . replace ( / \. g i t $ / , '' ) ) ;
727735
728736 const repo : RepoData = {
729737 external_codeHostType : 'genericGitHost' ,
@@ -787,7 +795,7 @@ export const compileAzureDevOpsConfig = async (
787795 }
788796
789797 const repoDisplayName = `${ repo . project . name } /${ repo . name } ` ;
790- const repoName = path . join ( repoNameRoot , repoDisplayName ) ;
798+ const repoName = path . posix . join ( repoNameRoot , repoDisplayName ) ;
791799 const isPublic = repo . project . visibility === ProjectVisibility . Public ;
792800
793801 if ( ! repo . remoteUrl ) {
0 commit comments