github.com/jenkins-x/jx/v2@v2.1.155/pkg/config/project_config.go (about)

     1  package config
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/jenkins-x/jx/v2/pkg/jenkinsfile"
     8  	"github.com/jenkins-x/jx/v2/pkg/tekton/syntax"
     9  	"github.com/pkg/errors"
    10  	"sigs.k8s.io/yaml"
    11  
    12  	"io/ioutil"
    13  	"path/filepath"
    14  	"reflect"
    15  
    16  	"github.com/jenkins-x/jx/v2/pkg/util"
    17  	corev1 "k8s.io/api/core/v1"
    18  )
    19  
    20  const (
    21  	// ProjectConfigFileName is the name of the project configuration file
    22  	ProjectConfigFileName = "jenkins-x.yml"
    23  )
    24  
    25  // +exported
    26  
    27  // ProjectConfig defines Jenkins X Pipelines usually stored inside the `jenkins-x.yml` file in projects
    28  type ProjectConfig struct {
    29  	// List of global environment variables to add to each branch build and each step
    30  	Env []corev1.EnvVar `json:"env,omitempty"`
    31  
    32  	PreviewEnvironments *PreviewEnvironmentConfig   `json:"previewEnvironments,omitempty"`
    33  	IssueTracker        *IssueTrackerConfig         `json:"issueTracker,omitempty"`
    34  	Chat                *ChatConfig                 `json:"chat,omitempty"`
    35  	Wiki                *WikiConfig                 `json:"wiki,omitempty"`
    36  	Addons              []*AddonConfig              `json:"addons,omitempty"`
    37  	BuildPack           string                      `json:"buildPack,omitempty"`
    38  	BuildPackGitURL     string                      `json:"buildPackGitURL,omitempty"`
    39  	BuildPackGitURef    string                      `json:"buildPackGitRef,omitempty"`
    40  	PipelineConfig      *jenkinsfile.PipelineConfig `json:"pipelineConfig,omitempty"`
    41  	NoReleasePrepare    bool                        `json:"noReleasePrepare,omitempty"`
    42  	DockerRegistryHost  string                      `json:"dockerRegistryHost,omitempty"`
    43  	DockerRegistryOwner string                      `json:"dockerRegistryOwner,omitempty"`
    44  }
    45  
    46  type PreviewEnvironmentConfig struct {
    47  	Disabled         bool `json:"disabled,omitempty"`
    48  	MaximumInstances int  `json:"maximumInstances,omitempty"`
    49  }
    50  
    51  type IssueTrackerConfig struct {
    52  	Kind    string `json:"kind,omitempty"`
    53  	URL     string `json:"url,omitempty"`
    54  	Project string `json:"project,omitempty"`
    55  }
    56  
    57  type WikiConfig struct {
    58  	Kind  string `json:"kind,omitempty"`
    59  	URL   string `json:"url,omitempty"`
    60  	Space string `json:"space,omitempty"`
    61  }
    62  
    63  type ChatConfig struct {
    64  	Kind             string `json:"kind,omitempty"`
    65  	URL              string `json:"url,omitempty"`
    66  	DeveloperChannel string `json:"developerChannel,omitempty"`
    67  	UserChannel      string `json:"userChannel,omitempty"`
    68  }
    69  
    70  type AddonConfig struct {
    71  	Name    string `json:"name,omitempty"`
    72  	Version string `json:"version,omitempty"`
    73  }
    74  
    75  // LoadProjectConfig loads the project configuration if there is a project configuration file
    76  func LoadProjectConfig(projectDir string) (*ProjectConfig, string, error) {
    77  	fileName := ProjectConfigFileName
    78  	if projectDir != "" {
    79  		fileName = filepath.Join(projectDir, fileName)
    80  	}
    81  	config, err := LoadProjectConfigFile(fileName)
    82  	return config, fileName, err
    83  }
    84  
    85  // LoadProjectConfigFile loads a specific project YAML configuration file
    86  func LoadProjectConfigFile(fileName string) (*ProjectConfig, error) {
    87  	config := ProjectConfig{}
    88  	exists, err := util.FileExists(fileName)
    89  	if err != nil || !exists {
    90  		return &config, err
    91  	}
    92  	data, err := ioutil.ReadFile(fileName)
    93  	if err != nil {
    94  		return &config, fmt.Errorf("Failed to load file %s due to %s", fileName, err)
    95  	}
    96  	validationErrors, err := util.ValidateYaml(&config, data)
    97  	if err != nil {
    98  		return &config, fmt.Errorf("failed to validate YAML file %s due to %s", fileName, err)
    99  	}
   100  	if len(validationErrors) > 0 {
   101  		return &config, fmt.Errorf("Validation failures in YAML file %s:\n%s", fileName, strings.Join(validationErrors, "\n"))
   102  	}
   103  	err = yaml.Unmarshal(data, &config)
   104  	if err != nil {
   105  		return &config, fmt.Errorf("Failed to unmarshal YAML file %s due to %s", fileName, err)
   106  	}
   107  	return &config, nil
   108  }
   109  
   110  // IsEmpty returns true if this configuration is empty
   111  func (c *ProjectConfig) IsEmpty() bool {
   112  	empty := &ProjectConfig{}
   113  	return reflect.DeepEqual(empty, c)
   114  }
   115  
   116  // SaveConfig saves the configuration file to the given project directory
   117  func (c *ProjectConfig) SaveConfig(fileName string) error {
   118  	data, err := yaml.Marshal(c)
   119  	if err != nil {
   120  		return err
   121  	}
   122  	err = ioutil.WriteFile(fileName, data, util.DefaultWritePermissions)
   123  	if err != nil {
   124  		return errors.Wrapf(err, "failed to save file %s", fileName)
   125  	}
   126  	return nil
   127  }
   128  
   129  // GetOrCreatePipelineConfig lazily creates a PipelineConfig if required
   130  func (c *ProjectConfig) GetOrCreatePipelineConfig() *jenkinsfile.PipelineConfig {
   131  	if c.PipelineConfig == nil {
   132  		c.PipelineConfig = &jenkinsfile.PipelineConfig{}
   133  	}
   134  	return c.PipelineConfig
   135  }
   136  
   137  // GetPipeline retrieves the parsed pipeline for the specified type
   138  func (c *ProjectConfig) GetPipeline(kind string) (*syntax.ParsedPipeline, error) {
   139  	var parsed *syntax.ParsedPipeline
   140  
   141  	if c.PipelineConfig == nil {
   142  		return nil, nil
   143  	}
   144  
   145  	switch kind {
   146  	case jenkinsfile.PipelineKindRelease:
   147  		if c.PipelineConfig.Pipelines.Release == nil {
   148  			parsed = nil
   149  		} else {
   150  			parsed = c.PipelineConfig.Pipelines.Release.Pipeline
   151  		}
   152  	case jenkinsfile.PipelineKindPullRequest:
   153  		if c.PipelineConfig.Pipelines.PullRequest == nil {
   154  			parsed = nil
   155  		} else {
   156  			parsed = c.PipelineConfig.Pipelines.PullRequest.Pipeline
   157  		}
   158  	case jenkinsfile.PipelineKindFeature:
   159  		if c.PipelineConfig.Pipelines.Feature == nil {
   160  			parsed = nil
   161  		} else {
   162  			parsed = c.PipelineConfig.Pipelines.Feature.Pipeline
   163  		}
   164  	default:
   165  		return nil, errors.Errorf("unknown pipeline kind %s", kind)
   166  	}
   167  
   168  	if parsed == nil {
   169  		return nil, errors.Errorf("no pipeline defined for kind %s", kind)
   170  	}
   171  	return parsed, nil
   172  }