2023-08-15 09:31:15 +00:00
// TODO #22198
2021-12-22 11:28:20 +00:00
import cleanGitRef from 'clean-git-ref' ;
2020-08-26 09:27:09 +00:00
import slugify from 'slugify' ;
2021-03-02 20:44:55 +00:00
import type { RenovateConfig } from '../../../config/types' ;
2020-08-26 09:27:09 +00:00
import { logger } from '../../../logger' ;
2023-07-24 22:54:28 +00:00
import { hash } from '../../../util/hash' ;
2021-10-27 14:37:11 +00:00
import { regEx } from '../../../util/regex' ;
2020-08-26 09:27:09 +00:00
import * as template from '../../../util/template' ;
2021-02-03 14:48:54 +00:00
const MIN_HASH_LENGTH = 6 ;
2021-10-27 14:37:11 +00:00
const RE_MULTIPLE_DASH = regEx ( /--+/g ) ;
2022-08-19 21:14:51 +00:00
2024-11-01 15:01:41 +00:00
const RE_SPECIAL_CHARS_STRICT = regEx ( /[`~!@#$%^&*()_=+[\]\\|{};':",.<>?/]/g ) ;
2022-08-19 21:14:51 +00:00
2020-08-26 09:27:09 +00:00
/ * *
* Clean git branch name
*
* Remove what clean - git - ref fails to :
* - leading dot / leading dot after slash
* - trailing dot
* - whitespace
2022-08-19 21:14:51 +00:00
* - special characters
* - leading or trailing dashes
2021-08-13 12:10:24 +00:00
* - chained dashes ( breaks markdown comments ) are replaced by single dash
2020-08-26 09:27:09 +00:00
* /
2022-08-19 21:14:51 +00:00
function cleanBranchName (
branchName : string ,
2024-11-01 15:01:41 +00:00
branchPrefix : string ,
2023-11-07 15:50:29 +00:00
branchNameStrict? : boolean ,
2022-08-19 21:14:51 +00:00
) : string {
let cleanedBranchName = branchName ;
2024-11-01 15:01:41 +00:00
let existingBranchPrefix = '' ;
2022-08-19 21:14:51 +00:00
if ( branchNameStrict ) {
2024-11-01 15:01:41 +00:00
if ( cleanedBranchName . startsWith ( branchPrefix ) ) {
existingBranchPrefix = branchPrefix ;
cleanedBranchName = cleanedBranchName . slice ( branchPrefix . length ) ;
}
cleanedBranchName =
existingBranchPrefix +
cleanedBranchName . replace ( RE_SPECIAL_CHARS_STRICT , '-' ) ; // massage out all special characters that slip through slugify
2022-08-19 21:14:51 +00:00
}
2021-12-22 11:28:20 +00:00
return cleanGitRef
2022-08-19 21:14:51 +00:00
. clean ( cleanedBranchName )
2021-10-27 14:37:11 +00:00
. replace ( regEx ( /^\.|\.$/ ) , '' ) // leading or trailing dot
. replace ( regEx ( /\/\./g ) , '/' ) // leading dot after slash
. replace ( regEx ( /\s/g ) , '' ) // whitespace
2022-08-19 21:14:51 +00:00
. replace ( regEx ( /[[\]?:\\^~]/g ) , '-' ) // massage out all these characters: [ ] ? : \ ^ ~
2021-11-12 15:36:54 +00:00
. replace ( regEx ( /(^|\/)-+/g ) , '$1' ) // leading dashes
. replace ( regEx ( /-+(\/|$)/g ) , '$1' ) // trailing dashes
2021-08-13 12:10:24 +00:00
. replace ( RE_MULTIPLE_DASH , '-' ) ; // chained dashes
2020-08-26 09:27:09 +00:00
}
export function generateBranchName ( update : RenovateConfig ) : void {
// Check whether to use a group name
2024-03-24 07:59:30 +00:00
const newMajor = String ( update . newMajor ) ;
const newMinor = String ( update . newMinor ) ;
2020-08-26 09:27:09 +00:00
if ( update . groupName ) {
2023-10-29 17:59:17 +00:00
update . groupName = template . compile ( update . groupName , update ) ;
2023-03-18 18:44:56 +00:00
logger . trace ( 'Using group branchName template' ) ;
2023-08-15 09:31:15 +00:00
// TODO: types (#22198)
2023-03-18 18:44:56 +00:00
logger . trace (
2023-11-07 15:50:29 +00:00
` Dependency ${ update . depName ! } is part of group ${ update . groupName } ` ,
2020-08-26 09:27:09 +00:00
) ;
2024-03-14 05:53:06 +00:00
if ( update . groupSlug ) {
update . groupSlug = template . compile ( update . groupSlug , update ) ;
} else {
update . groupSlug = update . groupName ;
}
update . groupSlug = slugify ( update . groupSlug , {
2020-08-26 09:27:09 +00:00
lower : true ,
} ) ;
if ( update . updateType === 'major' && update . separateMajorMinor ) {
2020-08-26 12:32:10 +00:00
if ( update . separateMultipleMajor ) {
2020-08-31 11:13:02 +00:00
update . groupSlug = ` major- ${ newMajor } - ${ update . groupSlug } ` ;
2020-08-26 12:32:10 +00:00
} else {
update . groupSlug = ` major- ${ update . groupSlug } ` ;
}
2020-08-26 09:27:09 +00:00
}
2024-03-24 07:59:30 +00:00
if ( update . updateType === 'minor' && update . separateMultipleMinor ) {
update . groupSlug = ` minor- ${ newMajor } . ${ newMinor } - ${ update . groupSlug } ` ;
}
2021-04-27 14:14:57 +00:00
if ( update . updateType === 'patch' && update . separateMinorPatch ) {
2020-08-26 09:27:09 +00:00
update . groupSlug = ` patch- ${ update . groupSlug } ` ;
}
2022-06-21 11:00:21 +00:00
update . branchTopic = update . group ! . branchTopic ? ? update . branchTopic ;
update . branchName = update . group ! . branchName ? ? update . branchName ;
2021-02-03 14:48:54 +00:00
}
if ( update . hashedBranchLength ) {
2022-06-20 09:47:07 +00:00
let hashLength = update . hashedBranchLength - update . branchPrefix ! . length ;
2022-02-19 09:57:01 +00:00
if ( hashLength < MIN_HASH_LENGTH ) {
2021-02-03 14:48:54 +00:00
logger . warn (
2023-11-07 15:50:29 +00:00
` \` hashedBranchLength \` must allow for at least ${ MIN_HASH_LENGTH } characters hashing in addition to \` branchPrefix \` . Using ${ MIN_HASH_LENGTH } character hash instead. ` ,
2021-02-03 14:48:54 +00:00
) ;
hashLength = MIN_HASH_LENGTH ;
}
2021-02-16 11:31:10 +00:00
const additionalBranchPrefix = template . compile (
2022-08-10 09:54:31 +00:00
String ( update . additionalBranchPrefix ? ? '' ) ,
2023-11-07 15:50:29 +00:00
update ,
2021-02-16 11:31:10 +00:00
) ;
2021-02-03 14:48:54 +00:00
2021-02-16 11:31:10 +00:00
const branchTopic = template . compile (
2022-08-10 09:54:31 +00:00
String ( update . branchTopic ? ? '' ) ,
2023-11-07 15:50:29 +00:00
update ,
2021-02-16 11:31:10 +00:00
) ;
2021-02-03 14:48:54 +00:00
let hashInput = additionalBranchPrefix + branchTopic ;
// Compile extra times in case of nested templates
hashInput = template . compile ( hashInput , update ) ;
hashInput = template . compile ( hashInput , update ) ;
2023-07-24 22:54:28 +00:00
const hashedInput = hash ( hashInput ) ;
2021-02-03 14:48:54 +00:00
2023-08-15 09:31:15 +00:00
// TODO: types (#22198)
2023-07-24 22:54:28 +00:00
update . branchName = ` ${ update . branchPrefix ! } ${ hashedInput . slice (
0 ,
2023-11-07 15:50:29 +00:00
hashLength ,
2023-07-24 22:54:28 +00:00
) } ` ;
2020-08-26 09:27:09 +00:00
} else {
2022-06-20 09:47:07 +00:00
update . branchName = template . compile ( update . branchName ! , update ) ;
2021-02-03 14:48:54 +00:00
// Compile extra times in case of nested templates
update . branchName = template . compile ( update . branchName , update ) ;
update . branchName = template . compile ( update . branchName , update ) ;
2020-08-26 09:27:09 +00:00
}
2024-03-24 07:59:30 +00:00
if ( update . updateType === 'minor' && update . separateMultipleMinor ) {
update . branchName = update . branchName . replace ( '.x' , ` . ${ newMinor } .x ` ) ;
}
2022-08-19 21:14:51 +00:00
update . branchName = cleanBranchName (
update . branchName ,
2024-11-01 15:01:41 +00:00
update . branchPrefix ! ,
2023-11-07 15:50:29 +00:00
update . branchNameStrict ,
2022-08-19 21:14:51 +00:00
) ;
2020-08-26 09:27:09 +00:00
}