github.com/jfrog/jfrog-cli-core/v2@v2.51.0/general/cisetup/pipelinesyaml.go (about) 1 package cisetup 2 3 import ( 4 "encoding/json" 5 "github.com/jfrog/jfrog-cli-core/v2/utils/coreutils" 6 "github.com/jfrog/jfrog-client-go/utils" 7 "github.com/jfrog/jfrog-client-go/utils/errorutils" 8 "gopkg.in/yaml.v3" 9 "strconv" 10 ) 11 12 const addRunFilesCmd = "add_run_files /tmp/jfrog/. jfrog" 13 14 type JFrogPipelinesYamlGenerator struct { 15 VcsIntName string 16 RtIntName string 17 SetupData *CiSetupData 18 } 19 20 func (yg *JFrogPipelinesYamlGenerator) Generate() (pipelineBytes []byte, pipelineName string, err error) { 21 pipelineName = yg.createPipelineName() 22 gitResourceName := yg.createGitResourceName() 23 biResourceName := yg.createBuildInfoResourceName() 24 gitResource := yg.createGitResource(gitResourceName) 25 biResource := yg.createBuildInfoResource(biResourceName) 26 pipeline, err := yg.createPipeline(pipelineName, gitResourceName, biResourceName) 27 if err != nil { 28 return nil, "", err 29 } 30 pipelineYaml := PipelineYml{ 31 Resources: []Resource{gitResource, biResource}, 32 Pipelines: []Pipeline{pipeline}, 33 } 34 pipelineBytes, err = yaml.Marshal(&pipelineYaml) 35 return pipelineBytes, pipelineName, errorutils.CheckError(err) 36 } 37 38 func (yg *JFrogPipelinesYamlGenerator) getNpmBashCommands(serverId, gitResourceName, convertedBuildCmd string) []string { 39 var commandsArray []string 40 commandsArray = append(commandsArray, getCdToResourceCmd(gitResourceName)) 41 commandsArray = append(commandsArray, getJfrogCliConfigCmd(yg.RtIntName, serverId, true)) 42 commandsArray = append(commandsArray, getBuildToolConfigCmd(npmConfigCmdName, serverId, yg.SetupData.BuiltTechnology.VirtualRepo)) 43 commandsArray = append(commandsArray, convertedBuildCmd) 44 commandsArray = append(commandsArray, jfrogCliBag) 45 commandsArray = append(commandsArray, jfrogCliBce) 46 return commandsArray 47 } 48 49 // Converts build tools commands to run via JFrog CLI. 50 func (yg *JFrogPipelinesYamlGenerator) convertNpmBuildCmd() (string, error) { 51 // Replace npm-i. 52 converted, err := replaceCmdWithRegexp(yg.SetupData.BuiltTechnology.BuildCmd, npmInstallRegexp, npmInstallRegexpReplacement) 53 if err != nil { 54 return "", err 55 } 56 // Replace npm-ci. 57 return replaceCmdWithRegexp(converted, npmCiRegexp, npmCiRegexpReplacement) 58 } 59 60 func replaceCmdWithRegexp(buildCmd, cmdRegexp, replacement string) (string, error) { 61 regexp, err := utils.GetRegExp(cmdRegexp) 62 if err != nil { 63 return "", err 64 } 65 return regexp.ReplaceAllString(buildCmd, replacement), nil 66 } 67 68 func (yg *JFrogPipelinesYamlGenerator) getPipelineEnvVars() map[string]string { 69 return map[string]string{ 70 coreutils.CI: strconv.FormatBool(true), 71 buildNameEnvVar: yg.SetupData.BuildName, 72 buildNumberEnvVar: runNumberEnvVar, 73 buildUrlEnvVar: stepUrlEnvVar, 74 } 75 } 76 77 func (yg *JFrogPipelinesYamlGenerator) createGitResource(gitResourceName string) Resource { 78 return Resource{ 79 Name: gitResourceName, 80 ResourceType: GitRepo, 81 ResourceConfiguration: GitRepoResourceConfiguration{ 82 Path: yg.SetupData.GetRepoFullName(), 83 GitProvider: yg.VcsIntName, 84 BuildOn: BuildOn{ 85 PullRequestCreate: true, 86 }, 87 Branches: IncludeExclude{Include: yg.SetupData.GitBranch}, 88 }, 89 } 90 } 91 92 func (yg *JFrogPipelinesYamlGenerator) createBuildInfoResource(buildInfoResourceName string) Resource { 93 return Resource{ 94 Name: buildInfoResourceName, 95 ResourceType: BuildInfo, 96 ResourceConfiguration: BuildInfoResourceConfiguration{ 97 SourceArtifactoryIntegration: yg.RtIntName, 98 BuildName: yg.SetupData.BuildName, 99 BuildNumber: runNumberEnvVar, 100 }, 101 } 102 } 103 104 func (yg *JFrogPipelinesYamlGenerator) createPipeline(pipelineName, gitResourceName, buildInfoResourceName string) (Pipeline, error) { 105 steps, err := yg.createSteps(gitResourceName, buildInfoResourceName) 106 if err != nil { 107 return Pipeline{}, err 108 } 109 return Pipeline{ 110 Name: pipelineName, 111 Steps: steps, 112 Configuration: PipelineConfiguration{ 113 PipelineEnvVars: PipelineEnvVars{ 114 ReadOnlyEnvVars: yg.getPipelineEnvVars(), 115 }, 116 }, 117 }, nil 118 } 119 120 func (yg *JFrogPipelinesYamlGenerator) createSteps(gitResourceName, buildInfoResourceName string) (steps []PipelineStep, err error) { 121 var step PipelineStep 122 123 switch yg.SetupData.BuiltTechnology.Type { 124 case coreutils.Maven: 125 step = yg.createMavenStep(gitResourceName) 126 case coreutils.Gradle: 127 step = yg.createGradleStep(gitResourceName) 128 case coreutils.Npm: 129 step, err = yg.createNpmStep(gitResourceName) 130 if err != nil { 131 return nil, err 132 } 133 } 134 135 return []PipelineStep{step, yg.createBuildInfoStep(gitResourceName, step.Name, buildInfoResourceName)}, nil 136 } 137 138 func (yg *JFrogPipelinesYamlGenerator) createMavenStep(gitResourceName string) PipelineStep { 139 return PipelineStep{ 140 Name: createTechStepName(MvnBuild), 141 StepType: MvnBuild, 142 Configuration: &MavenStepConfiguration{ 143 NativeStepConfiguration: yg.getDefaultNativeStepConfiguration(gitResourceName), 144 MvnCommand: yg.SetupData.GetBuildCmdForNativeStep(), 145 ResolverSnapshotRepo: yg.SetupData.BuiltTechnology.VirtualRepo, 146 ResolverReleaseRepo: yg.SetupData.BuiltTechnology.VirtualRepo, 147 }, 148 Execution: StepExecution{ 149 OnFailure: yg.getOnFailureCommands(), 150 }, 151 } 152 } 153 154 func (yg *JFrogPipelinesYamlGenerator) getDefaultNativeStepConfiguration(gitResourceName string) NativeStepConfiguration { 155 step := NativeStepConfiguration{ 156 BaseStepConfiguration: BaseStepConfiguration{ 157 EnvironmentVariables: map[string]string{ 158 buildStatusEnvVar: passResult, 159 }, 160 Integrations: []StepIntegration{ 161 { 162 Name: yg.RtIntName, 163 }, 164 }, 165 InputResources: []StepResource{ 166 { 167 Name: gitResourceName, 168 }, 169 }, 170 }, 171 AutoPublishBuildInfo: false, 172 ForceXrayScan: false, 173 } 174 return step 175 } 176 177 func (yg *JFrogPipelinesYamlGenerator) createGradleStep(gitResourceName string) PipelineStep { 178 return PipelineStep{ 179 Name: createTechStepName(GradleBuild), 180 StepType: GradleBuild, 181 Configuration: &GradleStepConfiguration{ 182 NativeStepConfiguration: yg.getDefaultNativeStepConfiguration(gitResourceName), 183 GradleCommand: yg.SetupData.GetBuildCmdForNativeStep(), 184 ResolverRepo: yg.SetupData.BuiltTechnology.VirtualRepo, 185 }, 186 Execution: StepExecution{ 187 OnFailure: yg.getOnFailureCommands(), 188 }, 189 } 190 } 191 192 func (yg *JFrogPipelinesYamlGenerator) createNpmStep(gitResourceName string) (PipelineStep, error) { 193 serverId := yg.createServerIdName() 194 195 converted, err := yg.convertNpmBuildCmd() 196 if err != nil { 197 return PipelineStep{}, err 198 } 199 200 commands := yg.getNpmBashCommands(serverId, gitResourceName, converted) 201 202 step := PipelineStep{ 203 Name: createTechStepName(NpmBuild), 204 StepType: Bash, 205 Configuration: &BaseStepConfiguration{ 206 EnvironmentVariables: map[string]string{ 207 buildStatusEnvVar: passResult, 208 }, 209 InputResources: []StepResource{ 210 { 211 Name: gitResourceName, 212 }, 213 }, 214 Integrations: []StepIntegration{ 215 { 216 Name: yg.RtIntName, 217 }, 218 }, 219 }, 220 Execution: StepExecution{ 221 OnExecute: commands, 222 OnComplete: []string{addRunFilesCmd}, 223 OnFailure: yg.getOnFailureCommands(), 224 }, 225 } 226 return step, nil 227 } 228 229 func (yg *JFrogPipelinesYamlGenerator) createBuildInfoStep(gitResourceName, previousStepName, buildInfoResourceName string) PipelineStep { 230 return PipelineStep{ 231 Name: createTechStepName(PublishBuildInfo), 232 StepType: PublishBuildInfo, 233 Configuration: &NativeStepConfiguration{ 234 BaseStepConfiguration: BaseStepConfiguration{ 235 InputSteps: []InputStep{ 236 { 237 Name: previousStepName, 238 }, 239 }, 240 InputResources: []StepResource{ 241 { 242 Name: gitResourceName, 243 }, 244 }, 245 OutputResources: []StepResource{ 246 { 247 Name: buildInfoResourceName, 248 }, 249 }, 250 }, 251 ForceXrayScan: true, 252 }, 253 Execution: StepExecution{ 254 OnComplete: []string{yg.getUpdateCommitStatusCmd(gitResourceName)}, 255 }, 256 } 257 } 258 259 type PipelineYml struct { 260 Resources []Resource `yaml:"resources,omitempty"` 261 Pipelines []Pipeline `yaml:"pipelines,omitempty"` 262 } 263 264 type ResourceType string 265 266 const ( 267 GitRepo ResourceType = "GitRepo" 268 BuildInfo ResourceType = "BuildInfo" 269 ) 270 271 type Resource struct { 272 Name string `yaml:"name,omitempty"` 273 ResourceType `yaml:"type,omitempty"` 274 ResourceConfiguration `yaml:"configuration,omitempty"` 275 } 276 277 type ResourceConfiguration interface { 278 ResourceConfigurationMarkerFunction() 279 } 280 281 type GitRepoResourceConfiguration struct { 282 Path string `yaml:"path,omitempty"` 283 GitProvider string `yaml:"gitProvider,omitempty"` 284 BuildOn `yaml:"buildOn,omitempty"` 285 Branches IncludeExclude `yaml:"branches,omitempty"` 286 } 287 288 func (g GitRepoResourceConfiguration) ResourceConfigurationMarkerFunction() {} 289 290 type BuildInfoResourceConfiguration struct { 291 SourceArtifactoryIntegration string `yaml:"sourceArtifactory,omitempty"` 292 BuildName string `yaml:"buildName,omitempty"` 293 BuildNumber json.Number `yaml:"buildNumber,omitempty"` 294 } 295 296 func (b BuildInfoResourceConfiguration) ResourceConfigurationMarkerFunction() {} 297 298 type IncludeExclude struct { 299 Include string `yaml:"include,omitempty"` 300 Exclude string `yaml:"exclude,omitempty"` 301 } 302 303 type BuildOn struct { 304 PullRequestCreate bool `yaml:"pullRequestCreate,omitempty"` 305 Commit bool `yaml:"commit,omitempty"` 306 } 307 308 type Pipeline struct { 309 Name string `yaml:"name,omitempty"` 310 Configuration PipelineConfiguration `yaml:"configuration,omitempty"` 311 Steps []PipelineStep `yaml:"steps,omitempty"` 312 } 313 314 type PipelineConfiguration struct { 315 Runtime `yaml:"runtime,omitempty"` 316 PipelineEnvVars `yaml:"environmentVariables,omitempty"` 317 } 318 319 type PipelineEnvVars struct { 320 ReadOnlyEnvVars map[string]string `yaml:"readOnly,omitempty"` 321 } 322 323 type RuntimeType string 324 325 const ( 326 Image RuntimeType = "image" 327 ) 328 329 type Runtime struct { 330 RuntimeType `yaml:"type,omitempty"` 331 Image RuntimeImage `yaml:"image,omitempty"` 332 } 333 334 type RuntimeImage struct { 335 Custom CustomImage `yaml:"custom,omitempty"` 336 } 337 338 type CustomImage struct { 339 Name string `yaml:"name,omitempty"` 340 Tag string `yaml:"tag,omitempty"` 341 Options string `yaml:"options,omitempty"` 342 Registry string `yaml:"registry,omitempty"` 343 SourceRepository string `yaml:"sourceRepository,omitempty"` 344 Region string `yaml:"region,omitempty"` 345 } 346 347 type StepType string 348 349 const ( 350 MvnBuild StepType = "MvnBuild" 351 GradleBuild StepType = "GradleBuild" 352 NpmBuild StepType = "NpmBuild" 353 Bash StepType = "Bash" 354 PublishBuildInfo StepType = "PublishBuildInfo" 355 ) 356 357 type PipelineStep struct { 358 Name string `yaml:"name,omitempty"` 359 StepType `yaml:"type,omitempty"` 360 Configuration StepConfiguration `yaml:"configuration,omitempty"` 361 Execution StepExecution `yaml:"execution,omitempty"` 362 } 363 364 type StepConfiguration interface { 365 appendInputSteps([]InputStep) 366 } 367 368 type BaseStepConfiguration struct { 369 EnvironmentVariables map[string]string `yaml:"environmentVariables,omitempty"` 370 Integrations []StepIntegration `yaml:"integrations,omitempty"` 371 InputResources []StepResource `yaml:"inputResources,omitempty"` 372 OutputResources []StepResource `yaml:"outputResources,omitempty"` 373 InputSteps []InputStep `yaml:"inputSteps,omitempty"` 374 } 375 376 func (b *BaseStepConfiguration) appendInputSteps(steps []InputStep) { 377 b.InputSteps = append(b.InputSteps, steps...) 378 } 379 380 type NativeStepConfiguration struct { 381 BaseStepConfiguration `yaml:",inline"` 382 ForceXrayScan bool `yaml:"forceXrayScan,omitempty"` 383 FailOnScan bool `yaml:"failOnScan,omitempty"` 384 AutoPublishBuildInfo bool `yaml:"autoPublishBuildInfo,omitempty"` 385 } 386 387 type MavenStepConfiguration struct { 388 NativeStepConfiguration `yaml:",inline"` 389 MvnCommand string `yaml:"mvnCommand,omitempty"` 390 ResolverSnapshotRepo string `yaml:"resolverSnapshotRepo,omitempty"` 391 ResolverReleaseRepo string `yaml:"resolverReleaseRepo,omitempty"` 392 DeployerSnapshotRepo string `yaml:"deployerSnapshotRepo,omitempty"` 393 DeployerReleaseRepo string `yaml:"deployerReleaseRepo,omitempty"` 394 } 395 396 type GradleStepConfiguration struct { 397 NativeStepConfiguration `yaml:",inline"` 398 GradleCommand string `yaml:"gradleCommand,omitempty"` 399 ResolverRepo string `yaml:"resolverRepo,omitempty"` 400 UsesPlugin bool `yaml:"usesPlugin,omitempty"` 401 UseWrapper bool `yaml:"useWrapper,omitempty"` 402 } 403 404 type StepIntegration struct { 405 Name string `yaml:"name,omitempty"` 406 } 407 408 type StepResource struct { 409 Name string `yaml:"name,omitempty"` 410 } 411 412 type InputStep struct { 413 Name string `yaml:"name,omitempty"` 414 } 415 416 type StepExecution struct { 417 OnStart []string `yaml:"onStart,omitempty"` 418 OnExecute []string `yaml:"onExecute,omitempty"` 419 OnComplete []string `yaml:"onComplete,omitempty"` 420 OnSuccess []string `yaml:"onSuccess,omitempty"` 421 OnFailure []string `yaml:"onFailure,omitempty"` 422 } 423 424 func (yg *JFrogPipelinesYamlGenerator) getOnFailureCommands() []string { 425 return []string{getExportCmd(buildStatusEnvVar, failResult), 426 jfrogCliBce, 427 jfrogCliBp} 428 } 429 430 func (yg *JFrogPipelinesYamlGenerator) getUpdateCommitStatusCmd(gitResourceName string) string { 431 return updateCommitStatusCmd + " " + gitResourceName 432 } 433 434 func (yg *JFrogPipelinesYamlGenerator) createGitResourceName() string { 435 return createPipelinesSuitableName(yg.SetupData, "gitResource") 436 } 437 438 func (yg *JFrogPipelinesYamlGenerator) createBuildInfoResourceName() string { 439 return createPipelinesSuitableName(yg.SetupData, "buildInfoResource") 440 } 441 442 func (yg *JFrogPipelinesYamlGenerator) createPipelineName() string { 443 return createPipelinesSuitableName(yg.SetupData, "pipeline") 444 } 445 446 func (yg *JFrogPipelinesYamlGenerator) createServerIdName() string { 447 return createPipelinesSuitableName(yg.SetupData, "serverId") 448 } 449 450 func createTechStepName(stepType StepType) string { 451 return string(stepType) + "Step" 452 }