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  }