2019-10-24 10:59:58 +02:00
package cmd
import (
2019-10-25 14:58:59 +02:00
"encoding/json"
2019-10-24 10:59:58 +02:00
"fmt"
"io"
"os"
2020-02-06 10:08:15 +02:00
"path/filepath"
"strings"
2019-10-24 10:59:58 +02:00
2019-10-25 14:58:59 +02:00
"github.com/SAP/jenkins-library/pkg/config"
2019-11-11 10:52:44 +02:00
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/piperutils"
2019-10-25 14:58:59 +02:00
"github.com/pkg/errors"
2019-10-24 10:59:58 +02:00
"github.com/spf13/cobra"
)
2019-11-06 17:22:50 +02:00
// GeneralConfigOptions contains all global configuration options for piper binary
type GeneralConfigOptions struct {
CustomConfig string
DefaultConfig [ ] string //ordered list of Piper default configurations. Can be filePath or ENV containing JSON in format 'ENV:MY_ENV_VAR'
ParametersJSON string
2020-01-15 13:16:25 +02:00
EnvRootPath string
2020-01-29 14:17:54 +02:00
NoTelemetry bool
2019-11-06 17:22:50 +02:00
StageName string
StepConfigJSON string
StepMetadata string //metadata to be considered, can be filePath or ENV containing JSON in format 'ENV:MY_ENV_VAR'
StepName string
Verbose bool
2019-10-24 10:59:58 +02:00
}
var rootCmd = & cobra . Command {
Use : "piper" ,
Short : "Executes CI/CD steps from project 'Piper' " ,
Long : `
This project ' Piper ' binary provides a CI / CD step libary .
It contains many steps which can be used within CI / CD systems as well as directly on e . g . a developer ' s machine .
` ,
//ToDo: respect stageName to also come from parametersJSON -> first env.STAGE_NAME, second: parametersJSON, third: flag
}
2019-11-06 15:07:41 +02:00
// GeneralConfig contains global configuration flags for piper binary
2019-11-06 17:22:50 +02:00
var GeneralConfig GeneralConfigOptions
2019-10-24 10:59:58 +02:00
// Execute is the starting point of the piper command line tool
func Execute ( ) {
rootCmd . AddCommand ( ConfigCommand ( ) )
2019-10-31 14:57:29 +02:00
rootCmd . AddCommand ( VersionCommand ( ) )
2019-12-13 11:55:45 +02:00
rootCmd . AddCommand ( DetectExecuteScanCommand ( ) )
2019-10-30 10:20:25 +02:00
rootCmd . AddCommand ( KarmaExecuteTestsCommand ( ) )
2020-03-23 11:38:31 +02:00
rootCmd . AddCommand ( SonarExecuteScanCommand ( ) )
2020-01-24 15:30:27 +02:00
rootCmd . AddCommand ( KubernetesDeployCommand ( ) )
2019-12-05 15:22:38 +02:00
rootCmd . AddCommand ( XsDeployCommand ( ) )
2019-11-04 17:07:30 +02:00
rootCmd . AddCommand ( GithubPublishReleaseCommand ( ) )
2019-12-16 18:34:12 +02:00
rootCmd . AddCommand ( GithubCreatePullRequestCommand ( ) )
2020-02-10 15:53:12 +02:00
rootCmd . AddCommand ( CloudFoundryDeleteServiceCommand ( ) )
2020-02-04 12:43:27 +02:00
rootCmd . AddCommand ( AbapEnvironmentPullGitRepoCommand ( ) )
2020-01-28 00:40:53 +02:00
rootCmd . AddCommand ( CheckmarxExecuteScanCommand ( ) )
2020-02-25 15:33:34 +02:00
rootCmd . AddCommand ( MtaBuildCommand ( ) )
2020-02-06 17:16:34 +02:00
rootCmd . AddCommand ( ProtecodeExecuteScanCommand ( ) )
2020-02-28 14:09:46 +02:00
rootCmd . AddCommand ( MavenExecuteCommand ( ) )
2020-04-01 11:45:31 +02:00
rootCmd . AddCommand ( CloudFoundryCreateServiceKeyCommand ( ) )
2020-03-13 14:32:37 +02:00
rootCmd . AddCommand ( MavenBuildCommand ( ) )
2020-03-12 16:45:57 +02:00
rootCmd . AddCommand ( MavenExecuteStaticCodeChecksCommand ( ) )
2020-03-20 19:20:52 +02:00
rootCmd . AddCommand ( NexusUploadCommand ( ) )
2019-10-25 14:58:59 +02:00
addRootFlags ( rootCmd )
if err := rootCmd . Execute ( ) ; err != nil {
fmt . Println ( err )
os . Exit ( 1 )
}
}
func addRootFlags ( rootCmd * cobra . Command ) {
2019-11-06 17:22:50 +02:00
rootCmd . PersistentFlags ( ) . StringVar ( & GeneralConfig . CustomConfig , "customConfig" , ".pipeline/config.yml" , "Path to the pipeline configuration file" )
2019-11-21 17:09:57 +02:00
rootCmd . PersistentFlags ( ) . StringSliceVar ( & GeneralConfig . DefaultConfig , "defaultConfig" , [ ] string { ".pipeline/defaults.yaml" } , "Default configurations, passed as path to yaml file" )
2019-11-06 17:22:50 +02:00
rootCmd . PersistentFlags ( ) . StringVar ( & GeneralConfig . ParametersJSON , "parametersJSON" , os . Getenv ( "PIPER_parametersJSON" ) , "Parameters to be considered in JSON format" )
2020-01-15 13:16:25 +02:00
rootCmd . PersistentFlags ( ) . StringVar ( & GeneralConfig . EnvRootPath , "envRootPath" , ".pipeline" , "Root path to Piper pipeline shared environments" )
2019-11-06 17:22:50 +02:00
rootCmd . PersistentFlags ( ) . StringVar ( & GeneralConfig . StageName , "stageName" , os . Getenv ( "STAGE_NAME" ) , "Name of the stage for which configuration should be included" )
rootCmd . PersistentFlags ( ) . StringVar ( & GeneralConfig . StepConfigJSON , "stepConfigJSON" , os . Getenv ( "PIPER_stepConfigJSON" ) , "Step configuration in JSON format" )
2020-01-29 14:17:54 +02:00
rootCmd . PersistentFlags ( ) . BoolVar ( & GeneralConfig . NoTelemetry , "noTelemetry" , false , "Disables telemetry reporting" )
2019-11-06 17:22:50 +02:00
rootCmd . PersistentFlags ( ) . BoolVarP ( & GeneralConfig . Verbose , "verbose" , "v" , false , "verbose output" )
2019-10-24 10:59:58 +02:00
2019-10-25 14:58:59 +02:00
}
// PrepareConfig reads step configuration from various sources and merges it (defaults, config file, flags, ...)
func PrepareConfig ( cmd * cobra . Command , metadata * config . StepData , stepName string , options interface { } , openFile func ( s string ) ( io . ReadCloser , error ) ) error {
filters := metadata . GetParameterFilters ( )
2020-01-29 14:17:54 +02:00
// add telemetry parameter "collectTelemetryData" to ALL, GENERAL and PARAMETER filters
filters . All = append ( filters . All , "collectTelemetryData" )
filters . General = append ( filters . General , "collectTelemetryData" )
filters . Parameters = append ( filters . Parameters , "collectTelemetryData" )
2020-01-15 13:16:25 +02:00
resourceParams := metadata . GetResourceParameters ( GeneralConfig . EnvRootPath , "commonPipelineEnvironment" )
2019-10-25 14:58:59 +02:00
flagValues := config . AvailableFlagValues ( cmd , & filters )
var myConfig config . Config
var stepConfig config . StepConfig
2019-11-06 17:22:50 +02:00
if len ( GeneralConfig . StepConfigJSON ) != 0 {
2019-10-25 14:58:59 +02:00
// ignore config & defaults in favor of passed stepConfigJSON
2019-11-06 17:22:50 +02:00
stepConfig = config . GetStepConfigWithJSON ( flagValues , GeneralConfig . StepConfigJSON , filters )
2019-10-25 14:58:59 +02:00
} else {
// use config & defaults
2019-11-11 10:52:44 +02:00
var customConfig io . ReadCloser
var err error
2019-10-25 14:58:59 +02:00
//accept that config file and defaults cannot be loaded since both are not mandatory here
2019-12-11 11:13:23 +02:00
{
2020-02-06 10:08:15 +02:00
projectConfigFile := getProjectConfigFile ( GeneralConfig . CustomConfig )
2019-11-11 10:52:44 +02:00
2020-02-06 10:08:15 +02:00
exists , err := piperutils . FileExists ( projectConfigFile )
2019-12-11 11:13:23 +02:00
if exists {
2020-02-06 10:08:15 +02:00
if customConfig , err = openFile ( projectConfigFile ) ; err != nil {
2020-03-31 08:47:09 +02:00
return errors . Wrapf ( err , "Cannot read '%s'" , projectConfigFile )
2019-12-11 11:13:23 +02:00
}
} else {
2020-02-06 10:08:15 +02:00
log . Entry ( ) . Infof ( "Project config file '%s' does not exist. No project configuration available." , projectConfigFile )
2019-12-11 11:13:23 +02:00
customConfig = nil
}
2020-02-06 10:08:15 +02:00
2019-12-11 11:13:23 +02:00
}
2019-10-25 14:58:59 +02:00
var defaultConfig [ ] io . ReadCloser
2019-11-06 17:22:50 +02:00
for _ , f := range GeneralConfig . DefaultConfig {
2020-03-30 14:31:24 +02:00
fc , err := openFile ( f )
2020-03-31 08:47:09 +02:00
// only create error for non-default values
if err != nil && f != ".pipeline/defaults.yaml" {
return errors . Wrapf ( err , "config: getting defaults failed: '%v'" , f )
}
if err == nil {
defaultConfig = append ( defaultConfig , fc )
2020-03-30 14:31:24 +02:00
log . Entry ( ) . Infof ( "Added default config '%s'" , f )
}
2019-10-25 14:58:59 +02:00
}
2020-03-19 18:24:35 +02:00
stepConfig , err = myConfig . GetStepConfig ( flagValues , GeneralConfig . ParametersJSON , customConfig , defaultConfig , filters , metadata . Spec . Inputs . Parameters , resourceParams , GeneralConfig . StageName , stepName , metadata . Metadata . Aliases )
2019-10-25 14:58:59 +02:00
if err != nil {
return errors . Wrap ( err , "retrieving step configuration failed" )
}
2019-10-24 10:59:58 +02:00
}
2019-10-25 14:58:59 +02:00
2020-01-29 14:17:54 +02:00
if fmt . Sprintf ( "%v" , stepConfig . Config [ "collectTelemetryData" ] ) == "false" {
GeneralConfig . NoTelemetry = true
}
2020-01-28 00:40:53 +02:00
if ! GeneralConfig . Verbose {
if stepConfig . Config [ "verbose" ] != nil && stepConfig . Config [ "verbose" ] . ( bool ) {
log . SetVerbose ( stepConfig . Config [ "verbose" ] . ( bool ) )
}
}
2019-10-25 14:58:59 +02:00
confJSON , _ := json . Marshal ( stepConfig . Config )
json . Unmarshal ( confJSON , & options )
config . MarkFlagsWithValue ( cmd , stepConfig )
return nil
2019-10-24 10:59:58 +02:00
}
2020-02-06 10:08:15 +02:00
func getProjectConfigFile ( name string ) string {
var altName string
if ext := filepath . Ext ( name ) ; ext == ".yml" {
altName = fmt . Sprintf ( "%v.yaml" , strings . TrimSuffix ( name , ext ) )
} else if ext == "yaml" {
altName = fmt . Sprintf ( "%v.yml" , strings . TrimSuffix ( name , ext ) )
}
fileExists , _ := piperutils . FileExists ( name )
altExists , _ := piperutils . FileExists ( altName )
// configured filename will always take precedence, even if not existing
if ! fileExists && altExists {
return altName
}
return name
}