github.com/jfrog/jfrog-cli-core/v2@v2.51.0/common/build/buildinfoproperties.go (about) 1 package build 2 3 import ( 4 "net" 5 "net/url" 6 "os" 7 "strings" 8 9 "github.com/jfrog/jfrog-cli-core/v2/utils/config" 10 "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" 11 12 "github.com/jfrog/jfrog-cli-core/v2/common/project" 13 14 "github.com/jfrog/jfrog-client-go/auth" 15 "github.com/jfrog/jfrog-client-go/utils/errorutils" 16 "github.com/spf13/viper" 17 ) 18 19 const ( 20 HttpProxyEnvKey = "HTTP_PROXY" 21 HttpsProxyEnvKey = "HTTPS_PROXY" 22 NoProxyEnvKey = "NO_PROXY" 23 ) 24 25 type BuildConfigMapping map[project.ProjectType][]*map[string]string 26 27 var buildTypeConfigMapping = BuildConfigMapping{ 28 project.Maven: {&commonConfigMapping, &mavenConfigMapping}, 29 project.Gradle: {&commonConfigMapping, &gradleConfigMapping}, 30 } 31 32 // For key/value binding 33 const BuildName = "build.name" 34 const BuildNumber = "build.number" 35 const BuildProject = "build.project" 36 const BuildTimestamp = "build.timestamp" 37 const GeneratedBuildInfo = "buildInfo.generated" 38 const DeployableArtifacts = "deployable.artifacts.map" 39 const InsecureTls = "insecureTls" 40 41 const ResolverPrefix = "resolver." 42 const DeployerPrefix = "deployer." 43 44 const Repo = "repo" 45 const SnapshotRepo = "snapshotRepo" 46 const ReleaseRepo = "releaseRepo" 47 48 const ServerId = "serverId" 49 const Url = "url" 50 const Username = "username" 51 const Password = "password" 52 const DeployArtifacts = "artifacts" 53 54 const MavenDescriptor = "deployMavenDescriptors" 55 const IvyDescriptor = "deployIvyDescriptors" 56 const IvyPattern = "ivyPattern" 57 const ArtifactPattern = "artifactPattern" 58 const ForkCount = "forkCount" 59 60 const IncludePatterns = "includePatterns" 61 const ExcludePatterns = "excludePatterns" 62 const FilterExcludedArtifactsFromBuild = "filterExcludedArtifactsFromBuild" 63 64 // For path and temp files 65 const PropertiesTempPath = "jfrog/properties/" 66 67 const httpProxy = "proxy." 68 const NoProxy = "noProxy" 69 const Host = "host" 70 const Port = "port" 71 const httpsProxy = httpProxy + "https." 72 73 // Config mapping are used to create buildInfo properties file to be used by BuildInfo extractors. 74 // Build config provided by the user may contain other properties that will not be included in the properties file. 75 var defaultPropertiesValues = map[string]string{ 76 "publish.artifacts": "true", 77 "publish.buildInfo": "false", 78 "publish.unstable": "false", 79 "publish.maven": "false", 80 "publish.ivy": "false", 81 "buildInfoConfig.includeEnvVars": "false", 82 "buildInfoConfig.envVarsExcludePatterns": "*password*,*psw*,*secret*,*key*,*token*,*auth*", 83 "buildInfo.agent.name": coreutils.GetClientAgentName() + "/" + coreutils.GetClientAgentVersion(), 84 "org.jfrog.build.extractor.maven.recorder.activate": "true", 85 "buildInfo.env.extractor.used": "true", 86 "publish.forkCount": "3", 87 "publish.filterExcludedArtifactsFromBuild": "true", 88 } 89 90 var commonConfigMapping = map[string]string{ 91 "publish.buildInfo": "", 92 "publish.unstable": "", 93 "buildInfoConfig.includeEnvVars": "", 94 "buildInfoConfig.envVarsExcludePatterns": "", 95 "buildInfo.agent.name": "", 96 "resolve.contextUrl": ResolverPrefix + Url, 97 "resolve.username": ResolverPrefix + Username, 98 "resolve.password": ResolverPrefix + Password, 99 "publish.contextUrl": DeployerPrefix + Url, 100 "publish.username": DeployerPrefix + Username, 101 "publish.password": DeployerPrefix + Password, 102 "publish.artifacts": DeployerPrefix + DeployArtifacts, 103 "deploy.build.name": BuildName, 104 "deploy.build.number": BuildNumber, 105 "deploy.build.project": BuildProject, 106 "deploy.build.timestamp": BuildTimestamp, 107 "buildInfo.generated.build.info": GeneratedBuildInfo, 108 "buildInfo.deployable.artifacts.map": DeployableArtifacts, 109 "proxy.host": httpProxy + Host, 110 "proxy.port": httpProxy + Port, 111 "proxy.username": httpProxy + Username, 112 "proxy.password": httpProxy + Password, 113 "proxy.noProxy": httpProxy + NoProxy, 114 "proxy.https.host": httpsProxy + Host, 115 "proxy.https.port": httpsProxy + Port, 116 "proxy.https.username": httpsProxy + Username, 117 "publish.forkCount": ForkCount, 118 "insecureTls": InsecureTls, 119 } 120 121 var mavenConfigMapping = map[string]string{ 122 "org.jfrog.build.extractor.maven.recorder.activate": "", 123 "buildInfoConfig.artifactoryResolutionEnabled": "buildInfoConfig.artifactoryResolutionEnabled", 124 "resolve.repoKey": ResolverPrefix + ReleaseRepo, 125 "resolve.downSnapshotRepoKey": ResolverPrefix + SnapshotRepo, 126 "publish.repoKey": DeployerPrefix + ReleaseRepo, 127 "publish.snapshot.repoKey": DeployerPrefix + SnapshotRepo, 128 "publish.includePatterns": DeployerPrefix + IncludePatterns, 129 "publish.excludePatterns": DeployerPrefix + ExcludePatterns, 130 "publish.filterExcludedArtifactsFromBuild": DeployerPrefix + FilterExcludedArtifactsFromBuild, 131 } 132 133 var gradleConfigMapping = map[string]string{ 134 "buildInfo.env.extractor.used": "", 135 "org.jfrog.build.extractor.maven.recorder.activate": "", 136 "resolve.repoKey": ResolverPrefix + Repo, 137 "resolve.downSnapshotRepoKey": ResolverPrefix + Repo, 138 "publish.repoKey": DeployerPrefix + Repo, 139 "publish.snapshot.repoKey": DeployerPrefix + Repo, 140 "publish.maven": DeployerPrefix + MavenDescriptor, 141 "publish.ivy": DeployerPrefix + IvyDescriptor, 142 "publish.ivy.ivyPattern": DeployerPrefix + IvyPattern, 143 "publish.ivy.artPattern": DeployerPrefix + ArtifactPattern, 144 } 145 146 func ReadMavenConfig(path string, mvnProps map[string]any) (config *viper.Viper, err error) { 147 if path == "" { 148 config = createDefaultConfigWithParams(project.YAML, project.Maven.String(), mvnProps) 149 } else { 150 config, err = project.ReadConfigFile(path, project.YAML) 151 } 152 return 153 } 154 155 func createDefaultConfigWithParams(configType project.ConfigType, technology string, params map[string]any) *viper.Viper { 156 vConfig := viper.New() 157 vConfig.SetConfigType(string(configType)) 158 vConfig.Set("type", technology) 159 for key, value := range params { 160 vConfig.Set(key, value) 161 } 162 return vConfig 163 } 164 165 // Returns the Artifactory details 166 // Checks first for the deployer information if exists and if not, checks for the resolver information. 167 func GetServerDetails(vConfig *viper.Viper) (*config.ServerDetails, error) { 168 if vConfig.IsSet(DeployerPrefix + ServerId) { 169 serverId := vConfig.GetString(DeployerPrefix + ServerId) 170 return config.GetSpecificConfig(serverId, true, true) 171 } 172 173 if vConfig.IsSet(ResolverPrefix + ServerId) { 174 serverId := vConfig.GetString(ResolverPrefix + ServerId) 175 return config.GetSpecificConfig(serverId, true, true) 176 } 177 return nil, nil 178 } 179 180 func CreateBuildInfoProps(buildArtifactsDetailsFile string, config *viper.Viper, projectType project.ProjectType) (map[string]string, error) { 181 if config.GetString("type") != projectType.String() { 182 return nil, errorutils.CheckErrorf("Incompatible build config, expected: " + projectType.String() + " got: " + config.GetString("type")) 183 } 184 if err := setServerDetailsToConfig(ResolverPrefix, config); err != nil { 185 return nil, err 186 } 187 if err := setServerDetailsToConfig(DeployerPrefix, config); err != nil { 188 return nil, err 189 } 190 if err := setProxyIfDefined(config); err != nil { 191 return nil, err 192 } 193 if buildArtifactsDetailsFile != "" { 194 config.Set(DeployableArtifacts, buildArtifactsDetailsFile) 195 } 196 return createProps(config, projectType), nil 197 } 198 199 func createProps(config *viper.Viper, projectType project.ProjectType) map[string]string { 200 props := make(map[string]string) 201 // Iterate over all the required properties keys according to the buildType and create properties file. 202 // If a value is provided by the build config file write it, 203 // otherwise use the default value from defaultPropertiesValues map. 204 for _, partialMapping := range buildTypeConfigMapping[projectType] { 205 for propKey, configKey := range *partialMapping { 206 var value string 207 if config.IsSet(configKey) { 208 value = config.GetString(configKey) 209 } else if defaultVal, ok := defaultPropertiesValues[propKey]; ok { 210 value = defaultVal 211 } 212 if value != "" { 213 props[propKey] = value 214 // Properties that have the 'artifactory.' prefix are deprecated. 215 // For backward compatibility reasons, both will be added to the props map. 216 if !strings.HasPrefix(propKey, "artifactory.") { 217 props["artifactory."+propKey] = value 218 } 219 } 220 } 221 } 222 return props 223 } 224 225 // If one of the HTTP_PROXY, HTTPS_PROXY or No_PROXY environment variables are set, add to the config proxy details. 226 func setProxyIfDefined(config *viper.Viper) error { 227 setNoProxyIfDefined(config) 228 if err := setHttpProxy(config); err != nil { 229 return err 230 } 231 return setHttpsProxy(config) 232 } 233 234 func setHttpProxy(config *viper.Viper) error { 235 var proxyConfig string 236 if proxyConfig = os.Getenv(HttpProxyEnvKey); proxyConfig == "" { 237 return nil 238 } 239 host, port, username, password, err := parseProxy(proxyConfig) 240 if err != nil { 241 return err 242 } 243 config.Set(httpProxy+Host, host) 244 config.Set(httpProxy+Port, port) 245 config.Set(httpProxy+Username, username) 246 return os.Setenv(httpProxy+Password, password) 247 } 248 249 func setHttpsProxy(config *viper.Viper) error { 250 var proxyConfig string 251 if proxyConfig = os.Getenv(HttpsProxyEnvKey); proxyConfig == "" { 252 return nil 253 } 254 host, port, username, password, err := parseProxy(proxyConfig) 255 if err != nil { 256 return err 257 } 258 config.Set(httpsProxy+Host, host) 259 config.Set(httpsProxy+Port, port) 260 config.Set(httpsProxy+Username, username) 261 return os.Setenv(httpsProxy+Password, password) 262 } 263 264 func setNoProxyIfDefined(config *viper.Viper) { 265 noProxy := os.Getenv(NoProxyEnvKey) 266 if noProxy != "" { 267 config.Set(httpProxy+NoProxy, noProxy) 268 } 269 } 270 271 func parseProxy(proxy string) (host string, port string, username string, password string, err error) { 272 url, err := url.Parse(proxy) 273 if err != nil { 274 err = errorutils.CheckError(err) 275 return 276 } 277 host, port, err = net.SplitHostPort(url.Host) 278 if err != nil { 279 err = errorutils.CheckError(err) 280 return 281 } 282 password, _ = url.User.Password() 283 username = url.User.Username() 284 return 285 } 286 287 func setServerDetailsToConfig(contextPrefix string, vConfig *viper.Viper) error { 288 if !vConfig.IsSet(contextPrefix + ServerId) { 289 return nil 290 } 291 292 serverId := vConfig.GetString(contextPrefix + ServerId) 293 artDetails, err := config.GetSpecificConfig(serverId, true, true) 294 if err != nil { 295 return err 296 } 297 if artDetails.GetArtifactoryUrl() == "" { 298 return errorutils.CheckErrorf("Server ID " + serverId + ": URL is required.") 299 } 300 vConfig.Set(contextPrefix+Url, artDetails.GetArtifactoryUrl()) 301 302 username := artDetails.GetUser() 303 password := artDetails.GetPassword() 304 if artDetails.GetAccessToken() != "" { 305 if username == "" { 306 username = auth.ExtractUsernameFromAccessToken(artDetails.GetAccessToken()) 307 } 308 password = artDetails.GetAccessToken() 309 } 310 vConfig.Set(contextPrefix+Username, username) 311 vConfig.Set(contextPrefix+Password, password) 312 return nil 313 }