@@ -84,7 +84,7 @@ function loadVarlockConfig() {
8484 const userConfigStr = readFileSync ( userVarlockConfigFilePath , 'utf-8' ) ;
8585 userVarlockConfig = userConfigStr . trim ( ) ? JSON . parse ( userConfigStr ) : undefined ;
8686 } catch ( err ) {
87- // file does not exist (we jsut do this to avoid doing an extra step to check)
87+ // file does not exist (we just do this to avoid doing an extra step to check)
8888 if ( err instanceof Error && 'code' in err && err . code === 'ENOENT' ) {
8989 debug ( `User varlock config file not found - ${ userVarlockConfigFilePath } ` ) ;
9090 } else if ( err instanceof SyntaxError ) {
@@ -102,7 +102,7 @@ function loadVarlockConfig() {
102102 const projectConfigStr = readFileSync ( projectVarlockConfigPath , 'utf-8' ) ;
103103 projectVarlockConfig = projectConfigStr . trim ( ) ? JSON . parse ( projectConfigStr ) : undefined ;
104104 } catch ( err ) {
105- // file does not exist (we jsut do this to avoid doing an extra step to check)
105+ // file does not exist (we just do this to avoid doing an extra step to check)
106106 if ( err instanceof Error && 'code' in err && err . code === 'ENOENT' ) {
107107 debug ( `Project varlock config file not found - ${ projectVarlockConfigPath } ` ) ;
108108 } else if ( err instanceof SyntaxError ) {
@@ -216,31 +216,71 @@ function anonymizeValue(payload: BinaryLike): string {
216216 return hash . digest ( 'hex' ) ;
217217}
218218
219- function getProjectGitRemoteUrl ( ) : string | undefined {
219+
220+ // known CI providers which have owner/repo available as env vars
221+ // we should order these by popularity (most popular first)
222+ const OWNER_REPO_CI_ENV_VARS = [
223+ 'GITHUB_ACTION_REPOSITORY' , // github actions
224+ [ 'NEXT_PUBLIC_VERCEL_GIT_REPO_OWNER' , 'NEXT_PUBLIC_VERCEL_GIT_REPO_SLUG' ] , // vercel
225+ ] ;
226+
227+ function getProjectOwnerRepoName ( ) : string | undefined {
228+ // check all known providers which set env vars that have this permission (only for CI)
229+ if ( isCI ) {
230+ for ( const envVarNames of OWNER_REPO_CI_ENV_VARS ) {
231+ if ( Array . isArray ( envVarNames ) ) {
232+ if ( process . env [ envVarNames [ 0 ] ] ) {
233+ return `${ process . env [ envVarNames [ 0 ] ] } /${ process . env [ envVarNames [ 1 ] ] } ` ;
234+ }
235+ } else {
236+ if ( process . env [ envVarNames ] ) {
237+ return process . env [ envVarNames ] ;
238+ }
239+ }
240+ }
241+ }
242+
243+ // otherwise, we'll try to extract the owner/repo name from the .git/config in remote url
220244 findProjectDirs ( ) ; // finds the git folder
221245 if ( ! _gitDirPath ) return undefined ;
246+ let remoteUrl : string | undefined ;
222247 try {
223248 const gitConfigContents = readFileSync ( join ( _gitDirPath , 'config' ) , 'utf-8' ) ;
224249 // first look for upstream
225250 const remoteUpstreamPos = gitConfigContents . indexOf ( '[remote "upstream"]' ) ;
226251 if ( remoteUpstreamPos !== - 1 ) {
227- const remoteUpstreamUrl = gitConfigContents . slice ( remoteUpstreamPos ) . match ( / u r l = ( .+ ) / ) ?. [ 1 ] ;
228- return remoteUpstreamUrl ;
252+ remoteUrl = gitConfigContents . slice ( remoteUpstreamPos ) . match ( / u r l = ( .+ ) / ) ?. [ 1 ] ;
253+ } else {
254+ // otherwise fallback to origin
255+ const remoteOriginPos = gitConfigContents . indexOf ( '[remote "origin"]' ) ;
256+ if ( remoteOriginPos === - 1 ) return undefined ;
257+ remoteUrl = gitConfigContents . slice ( remoteOriginPos ) . match ( / u r l = ( .+ ) / ) ?. [ 1 ] ;
229258 }
230- // otherwise fallback to origin
231- const remoteOriginPos = gitConfigContents . indexOf ( '[remote "origin"]' ) ;
232- if ( remoteOriginPos === - 1 ) return undefined ;
233- const remoteOriginUrl = gitConfigContents . slice ( remoteOriginPos ) . match ( / u r l = ( .+ ) / ) ?. [ 1 ] ;
234- return remoteOriginUrl ;
235259 } catch ( err ) {
236260 return undefined ;
237261 }
262+ if ( ! remoteUrl ) return undefined ;
263+
264+
265+ remoteUrl = remoteUrl
266+ . replace ( / \? .* $ / , '' ) // remove query params
267+ . replace ( / \. g i t $ / , '' ) ; // remove git suffix
268+
269+ const protocol = remoteUrl . includes ( '://' ) ? remoteUrl . split ( '://' ) [ 0 ] . toLowerCase ( ) : undefined ;
270+ if ( protocol && [ 'https' , 'http' , 'git' , 'ssh' ] . includes ( protocol . toLowerCase ( ) ) ) {
271+ // ex: https://github.com/owner/repo.git
272+ return remoteUrl . split ( '/' ) . slice ( - 2 ) . join ( '/' ) . replace ( / \. g i t $ / , '' ) ;
273+ } else if ( remoteUrl ?. startsWith ( 'git@' ) ) {
274+ // ex: git@github .com:owner/repo.git
275+ return remoteUrl . split ( ':' ) [ 1 ] ?. replace ( / \. g i t $ / , '' ) ;
276+ }
277+ return undefined ;
238278}
239279function getAnonymousProjectId ( ) {
240280 // we want a project ID tied to the git repo, so we can group telemetry data by project
241- // we could use the first commit hash, but this is more costly to compute, as we either need to rely
242- // on the git cli and execSync, or we need to parse the git objects directly
243- // so for now, we'll use the git remote URL (upstream if it exists, or origin)
281+ // Astro uses first commit hash, but it's costly to compute needing git cli and execSync, or parsing the git objects directly
282+ // so we will try to determing the git owner/repo name from . git/config or env vars
283+ // and then anonymize it
244284 const gitRemoteUrl = getProjectGitRemoteUrl ( ) ;
245285 if ( ! gitRemoteUrl ) return null ;
246286 return anonymizeValue ( gitRemoteUrl ) ;
0 commit comments