1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00
sap-jenkins-library/cmd/piper.go
Daniel Bernd 0d8bd7dc52
Add step abapEnvironmentPushATCSystemConfig (#3426)
* Checkin Go File - Push ATC Config

* ATC Push Config - Testfile

* Initial generated go files for ATC System Configuration

* ApiProxyUpload Command (#3295)

* ApiProxyUpload Command

* Code Review Fixes

* CodeReview Changes

* CodeReview Fixes

* YAML fixes

* CodeReview Fix

* Code Review Fixes

* CodeReview Fixes

* Code Climate Fixes

* Code Review Fixes

* Code Review Fixes

Co-authored-by: Roland Stengel <r.stengel@sap.com>
Co-authored-by: Oliver Feldmann <oliver.feldmann@sap.com>

* Fetch Xcrsf-Token

* Update  abapEnvironmentPushATCSystemConfig.yaml

* docs: fix urls (#3400)

* fix stash and adapt unit tests accordingly (#3403)

* Push ATC System Configuration - File read, send request, parse response

* fetchATCXcsrfToken

* fix(whitesourceExecuteScan): added missing credential declaration for the docker config (#3404)

* insert command in piper.go

* feat(cnbBuild): remove docker config after parsing (#3417)

Co-authored-by: Philipp Stehle <philipp.stehle@sap.com>

* more funcs

* more funcs

* Revert "feat: Add debug output to getConfig (#3341)" (#3396)

This reverts commit b760bf48e7.

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* feat (kubernetesDeploy) allow secret creation in cluster with kubectl as deploy tool (#3398)

* defaulting deocker config json location

* function change

* harmonising secret creation via json config apply

* adding the env path to kaniko

* env var

* adding path

* adding path

* adding path

* rolling back changes for path

* adapting condition for secret creation

* conditions based on username and password only

* fix unit test as per new secret creation

* update documentation with regards to secret creation

* fixing yaml lint empty line

* fixing trailing line from kaniko yaml

* error condition when path of the docker config json file is not found

Co-authored-by: anilkeshav27 <you@example.com>

* readPipelineEnv -> Serialize Directly to os.Stdout (#3180)

* Serialize CPE Directly to os.Stdout

* Response Error Handling 1

* Add easy mode for AUnit & ATC (#3389)

* remove mandatory flag from config files

* Enable repo.yml as config

* Adapt to merge

* Refactoring

* Refactoring

* avoid panic

* Add comments

* Add easy mode for atc

* Add tests

* Add test

* Refactor

* Add test for MPS

* Updates

* Rename functions

* Add files to gitignore

* Rename

* Renaming

* Renaming

* Renaming

* Improve error messages

* Update documentation

* Add logging

* Rename

* Extend gitignore

* fix(sonar): fix file patterns for gcs upload (#3406)

Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>

* testing piper forks  (#3420)

* developer doku update on how to test with forked repos
Co-authored-by: rosemarieB <45030247+rosemarieB@users.noreply.github.com>

* Error Messages parsing

* Update yaml parameter

* feat (npmExecuteScripts) create seperate npmrc file for publish to private repo (#3422)

* creating new npm rc file

* publishing to registry staging

* exposing base64 version of env variables

* changing encoding param

* fixing unit test for the new path

* debugging env var

* remove debug message

* update docu

* changing new npmrc file name

* adding new npmrc to ignore

* adding new npmrc to ignore

Co-authored-by: anilkeshav27 <you@example.com>

* minor

* small changes

* small changes

* UNIT Test

* Unit Test 2

* Update .gitignore

Co-authored-by: Daniel Mieg <56156797+DanielMieg@users.noreply.github.com>

* Update abapEnvironmentAddons.md: Unable to update target vectors with unchanged SWC version (#3392)

* Update abapEnvironmentAddons.md

* Update documentation/docs/scenarios/abapEnvironmentAddons.md

Co-authored-by: Daniel Mieg <56156797+DanielMieg@users.noreply.github.com>

* Update abapEnvironmentAddons.md

Co-authored-by: Daniel Mieg <56156797+DanielMieg@users.noreply.github.com>

* Returning earlier & parseOdataResp 1

* new Parameter for overwrite existing

* feat(cnbBuild): preserve maven test results in the workspace (#3429)

Co-authored-by: Pavel Busko <pavel.busko@sap.com>
Co-authored-by: Ralf Pannemans <ralf.pannemans@sap.com>

* Update Introduction (#3433)

* Check Existence of configuration

* Quote strings in addon.yml (#3435)

* including vaultSecretFile to parameter generator docu (#3436)

Co-authored-by: anilkeshav27 <you@example.com>

* fix: wrong command line format for multiple extension files (#3434)

* feat(cnbBuild) containerImageName will be defaulted if possible (#3437)

Co-authored-by: Ralf Pannemans <ralf.pannemans@sap.com>
Co-authored-by: Johannes Dillmann <j.dillmann@sap.com>
Co-authored-by: Sumit Kulhadia <sumit.kulhadia@sap.com>

* Corr. check existence

* check existence 2

* existence handling 2

* refinement existence handling & param rename

* config yaml change - no mandatory for bool param

* PATCH for existing Configuration

* fix: correct typo in log message (#3439)

Closes #3438

* feat(protecode): add versioning model (#3373)

* changes to detectExec before master merge

* changes for detectExecuteScan

* self generated code added

* fix syntax errors and update docu

* added unit tests for fail and Group

* fix failOn bug

* add Groups as string array

* add Groups as string array

* tests and validation for groups, failOn

* Updated docs and added more tests

* documentation md files should not be changed

* Handle merge conflicts from PR 1845

* fix merge errors

* remove duplicate groups, merge error

* adding buildCode and buildTool as params

* switching build options

* building maven modules

* parameter correction

* parameter correction

* gnerate with new build parameter

* adding comments

* removing piper lib master and modifying goUtils to download 1.5.7 release

* first cleaning then installing

* multi module maven built

* multi module maven built removing unwanted code

* multi module maven built moving inside switch

* testing

* modifying the default use case to also call maven build

* modifying the default use case to also call maven build wih --

* corrected maven build command

* corrected maven build command with %v

* skipping test runs

* testing for MTA project with single pom

* adding absolute path to m2 path

* clean up

* adding switch for mta and maven and removing env from containers

* commiting changes for new detect step

* correting log message

* code clean up

* unit tests changes to detectExecute

* basic tests for new change

* restoring piperGoUtils to download correct piper binary

* code clean up

* code clean up

* protecodeExecuteScan :: versioning model draft - 1

* protecodeExecuteScan :: version model draft-2

* protecodeExecuteScan :: changing filename and version concatenation

* protecodeExecuteScan :: update documentation

* protecodeExecuteScan :: double URL encoding has been corrected & console messaging improved

* protecodeExecuteScan :: fixed Go/generate validation fail

* protecodeExecuteScan :: fixing failed unit tests

* protecodeExecuteScan :: Version field added

* protecodeExecuteScan :: Version field add => minor changes

* protecodeExecuteScan :: Version field add => fixing tests

Co-authored-by: D072410 <giridhar.shenoy@sap.com>
Co-authored-by: Keshav <anil.keshav@sap.com>
Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>
Co-authored-by: Sven Merk <33895725+nevskrem@users.noreply.github.com>

* GCS Upload fixes (#3387)

* Fixed argument type in persist function

* Fixed gcp upload to be usable in internal piper

* Fixed import of packages

* Updated logs

Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>
Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* Unit Test 2

* Unit Tests

* Add gcs upload to mavenExecuteIntegration step (#3432)

* Add gcs upload to mavenExecuteIntegration step

* go generate

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* Check times refine

* Permwrite 0644

* disable http retry (#3447)

* Update maxWaitTime timeout for WhiteSource (#3284)

* Update scanPolling.go

Changing maxWaitTime from 15 to 30 to overcome WhiteSource results reflection in the backend issue.

* Update configHelper.go

* Reset configHelper changes to fix PR 3284

 Committer: raghunathd8

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
Co-authored-by: raghunathd8 <root@docker-evaluation.openstack.eu-nl-1.cloud.sap>
Co-authored-by: Sven Merk <33895725+nevskrem@users.noreply.github.com>

* removed trailing spaces

* yaml Update

* minor mock for token & Unit Tests

* rename Parameter Patch

* lil refactor & Unit Test

* fixes PATCH & more Unit Tests

* add log at certain points

* not writing configuration file back

* feat(malwareExecuteScan): refactoring and docker support (#3421)

* feat(malwareExecuteScan): add support for scanning docker images

* refactoring

* print out finding if available

* generate toolrecord for malware scan

* persist scan report

* docs

* fix

* fix

* rollback cmd/init_unix.go

* auhenticated pull

* fix

* fix: report shall be consistent with the api model

* gcs upload

* fix linter

* Fix potential nil reference (#3460)

* Add gcs upload to karmaExecuteTests step (#3431)

* Add gcs upload to karmaExecuteTests step

* go generate

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* Add gcs upload to gaugeExecuteTests step (#3410)

* Add gcs upload to gaugeExecuteTests step

* go generate

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* Add gcs upload to newmanExecute step (#3408)

* Add gcs upload to newmanExecute step

* go generate

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* feat(GitHub): fetch commit statistics (#3381)

* fetch GH statistics

* move GH and Sonar integration tests to own files

* fix imports

* add integration test case

* add result type

* Apply suggestions from code review

* feat: add command to fetch default files (#3445)

* some ideas..

* Add getDefaults command (WIP) (#3444)

* add getYAML function for configs

* create getDefaults command(based on getConfig)

* add getDefaults command to CLI

* read defaults files, using github tokens as well

* write defaults to stdout as JSON object with YAMLs embedded

* catch case where no input files are given

* actually write output to file if outputFile is specified

* mark defaultsFile flag as required

* add basic tests

* add output (string)  test

* adapt generateDefaults() to return output (used for test of previous commit)

* Changes to getDefaults() JSON output (#3449)

* change JSON output to contain separate fields

* filename -> filepath

* Apply suggestions from code review

* Apply suggestions from code review

* Update pkg/config/config_test.go

Co-authored-by: Jordi van Liempt <35920075+jliempt@users.noreply.github.com>

* BATCH request preparation

* Add gcs upload to mtaBuild step (#3405)

* Add gcs upload to mtaBuild

* Patterns was updated

* go generate

* removed patterns related to sapGenerateEnvironmentInfo step

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* Add gcs upload to mavenBuild step (#3394)

* Add gcs upload to mavenBuild step

* Patterns were updated

* go generate

* removed patterns related to sapGenerateEnvironmentInfo step

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* feat(gradleExecuteBuild): add stage scope to path parameter, fix project dir exist issue (#3401)

* add stage scope to path parameter, fix project dir exist issue

* fix unit test for gradleExecuteBuild

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* Add gcs upload to uiVeri5ExecuteTests step (#3409)

* Add gcs upload to uiVeri5ExecuteTests step

* go generate

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* Address further nil references (#3462)

* Address further nil references

* Message text

* Final checks

* fix (npmExecuteScripts) allow npm pack before npm publish (#3455)

* adding config to piperNpmr

* scope in cli

* adding scope to repo url and npmrc

* publish to scoped

* removing scope

* changing scope position

* adding scope to userconfig

* adding registry=

* pack and then tar

* not removing tmp folder

* adding flag

* pack before publish

* adding log

* debug

* debug with change directory

* publishing created tar ball

* debug

* üath

* adding main npmrc

* renaming old npmrc file

* error renaming old npmrc file

* renaming err

* correcting npmrc file path

* renaming file back to original

* current working directory

* renaming the npmrc file

* avoiding change directory

* with current working dir

* adding dot

* renaming npmrc and defer removal

* rename files

* Update pkg/npm/publish.go

* Update pkg/npm/publish.go

Co-authored-by: anilkeshav27 <you@example.com>
Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* Add testing for helm during acceptance stage (#3402)

* Add kubernetesDeploy to Acceptance

* Add more kubernetesDeploy

* Add helm tests

* Change documentation

* Fix docu

* Change generated

* Add tests

* Add groovy tests

* Fix tests

* Change tests

Co-authored-by: Thorsten Duda <thorsten.duda@sap.com>

* Batch Request for Patches

* Fix(gctsDeploy) : add client in config url, disable retry for create and pull (#3464)

* minor Unit Test correction

* lil cleanup

* lil refactoring

* removed nuneeded linebreaks

* refactoring Command on Entity in Batch

* some Unit Tests for Build Batch Request

* more Unittests - Build Batch Request

* fix(fortifyExecuteScan): User assignment based on PR ownership (#3472)

* Debug PR user details

* Check association

* Change to login

* Fix PR creator assignment

* Improve docs

* Fix test

* Update gradle version (#3476)

* Update gradle version

* Update generated file

* small correction Text & Test

* chore(kubernetesDeploy): add telemetry for deployTool (#3469)

* chore(kubernetesDeploy): add telemetry for deployTool

* Update cmd/kubernetesDeploy.go

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* rename Parameter patchIfExisting

* fix (mtaBuild) keep mtar artifact name in synch with maven gav (#3454)

* keep mtar name in synch with maven gav

* retaining slashes

* keeping dots in artifact name

Co-authored-by: anilkeshav27 <you@example.com>

* Update image for gradle build (#3479)

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* Last Changed not Zero check added

* Added pseudo_comment_policy in struct

* Unit Test adaption

* smaller refactoring, Unit Test, removed doubles

* fix(cnbBuild) do not add complete path to telemetry (#3487)

Co-authored-by: Ralf Pannemans <ralf.pannemans@sap.com>
Co-authored-by: Philipp Stehle <philipp.stehle@sap.com>

* Add limitation that table keys are exported generically (#3490)

* Add limitation that table keys are exported generically

* Fix formatting

* Clarify delta calculation of different package types (#3482)

Co-authored-by: tiloKo <70266685+tiloKo@users.noreply.github.com>

* Add troubleshooting for missing add-on registration (#3491)

Co-authored-by: tiloKo <70266685+tiloKo@users.noreply.github.com>

* feat (Documentation) documentation for mavenBuild and npmExecuteScripts that consume dependencies from a private repo. (#3484)

* build depdency docu for maven and npm

* removing trailing white space in yaml

* Update resources/metadata/mavenBuild.yaml

* relative url for vault and mta docu

* running go generate

* keeping vault relative path

* go generate

* reverting to global paths

* go generate

* wild card for a higher level dir

* searching on top folder only

* relative level above

* pointing to infrastructure

* correcting links

Co-authored-by: anilkeshav27 <you@example.com>
Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* fix(kanikoExecute): tmp dir (#3478)

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* feat(golangBuild): add support for publishing binaries (#3495)

* fix(golangBuild): keep track of the artifactversion in binary names (#3498)

* fix(golangBuild): keep track of the artifactversion in binary names

* improve the naming scheme

* fix (build dependency) typo corrections (#3494)

* typo corrections

* trailing white space

* go generate

Co-authored-by: anilkeshav27 <you@example.com>

* Revert "fix(golangBuild): keep track of the artifactversion in binary names (#3498)" (#3499)

This reverts commit ec783b0da6.

* sonarqube coverage: additional metrics (#3465)

* sonarqube coverage: additional metrics

* sonarExecuteScan: add lines of code and language distribution to sonarscan.json

* sonarExecuteScan: consider branch in componentService requests

* SonarQube: Do not omit empty values in SonarCoverage

* sonarExecuteScan: Add integration tests for ComponentService getLinesOfCode

* fix tests

* sonarExecuteScan: use pullRequest in componentService

Co-authored-by: I550025 <r.kloe@sap.com>
Co-authored-by: Marc Bormeth <marc.bormeth@sap.com>

* fix(golangBuild): targetRepositoryUrl (#3502)

* fix(golangBuild): targetRepositoryUrl

* regen

* fix(httpclient): folder permissions (#3506)

* fix(golangBuild): use PUT instead of POST (#3504)

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* feat(golangBuild): publish to subfolder (#3503)

* feat(golangBuild): publish to subfolder

* edge case handling

* fix

* fix(golangBuild): expect status 201 instead of 200 (#3508)

* feat(kanikoExecute): allow building multiple images (#3443)

* feat(kanikoExecute): allow building multiple images

* enhance tests

* chore: allow running tests in parallel

* small fixes

* fix: fix destination bug

* update formatting and defaults

* fix yml formatting

* chore: change cpe parameter names

* chore: improve variable naming

* Changes GetJobName value to repositoryname (#3509)

* Update npmExecuteScripts step (#3211)

* Update npmExecuteScripts step

* Fixed failing build

* Fixed path issue

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>
Co-authored-by: Christian Volk <christian.volk@sap.com>

* Ignore violations if failOn is NONE (#3513)

* fix(sonarExecuteScan): error handling for report metrics (#3512)

* Generic step   input from addon descriptor (#3467)

* enhance build step to run based on addon.yml in steampunk environment

Co-authored-by: tiloKo <70266685+tiloKo@users.noreply.github.com>

* feat(golangBuild): add BOM creation (#3496)

* Added BOM creation

* Fix cyclonedx install

* undo config.yml changes

* metadata was updated

* Update golangBuild.go

Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>

* If statement dearrangement

Co-authored-by: Daniel Bernd <93763187+danManSAP@users.noreply.github.com>
Co-authored-by: Mayur Belur Mohan <68264167+mayurmohan@users.noreply.github.com>
Co-authored-by: Roland Stengel <r.stengel@sap.com>
Co-authored-by: Oliver Feldmann <oliver.feldmann@sap.com>
Co-authored-by: Jordi van Liempt <35920075+jliempt@users.noreply.github.com>
Co-authored-by: Jesse Awan <jesse.awan@sap.com>
Co-authored-by: Pavel Busko <pavel.busko@sap.com>
Co-authored-by: Philipp Stehle <philipp.stehle@sap.com>
Co-authored-by: Marc Bormeth <marc.bormeth@sap.com>
Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
Co-authored-by: Anil Keshav <anil.keshav@sap.com>
Co-authored-by: anilkeshav27 <you@example.com>
Co-authored-by: tiloKo <70266685+tiloKo@users.noreply.github.com>
Co-authored-by: Daniel Mieg <56156797+DanielMieg@users.noreply.github.com>
Co-authored-by: Siarhei Pazdniakou <siarhei.pazdniakou@sap.com>
Co-authored-by: Christopher Fenner <26137398+CCFenner@users.noreply.github.com>
Co-authored-by: Peter Persiel <6087940+peterpersiel@users.noreply.github.com>
Co-authored-by: Ralf Pannemans <ralf.pannemans@sap.com>
Co-authored-by: Marcus Holl <marcus.holl@sap.com>
Co-authored-by: Johannes Dillmann <j.dillmann@sap.com>
Co-authored-by: Sumit Kulhadia <sumit.kulhadia@sap.com>
Co-authored-by: Nikolay Grechanov <nikolay.grechanov@sap.com>
Co-authored-by: Umidjon Urunov <79094563+UmidjonUrunov@users.noreply.github.com>
Co-authored-by: D072410 <giridhar.shenoy@sap.com>
Co-authored-by: Sven Merk <33895725+nevskrem@users.noreply.github.com>
Co-authored-by: Sarat Krishnan <78093145+sarat-krk@users.noreply.github.com>
Co-authored-by: Raghunath Deshpande <raghunath.deshpande@sap.com>
Co-authored-by: raghunathd8 <root@docker-evaluation.openstack.eu-nl-1.cloud.sap>
Co-authored-by: Christian Volk <christian.volk@sap.com>
Co-authored-by: Eugene Kortelyov <eugene.kortelyov@sap.com>
Co-authored-by: Linda Siebert <39100394+LindaSieb@users.noreply.github.com>
Co-authored-by: Thorsten Duda <thorsten.duda@sap.com>
Co-authored-by: Matthias Scudlik <matthias.scudlik@gmail.com>
Co-authored-by: I550025 <r.kloe@sap.com>
Co-authored-by: ffeldmann <f.feldmann@sap.com>
Co-authored-by: ManjunathMS35 <manjunathms35@gmail.com>
Co-authored-by: Matthias Scudlik <matthias.scudlik@sap.com>
Co-authored-by: rosemarieB <45030247+rosemarieB@users.noreply.github.com>
2022-02-08 16:14:29 +01:00

599 lines
24 KiB
Go

package cmd
import (
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"reflect"
"strconv"
"strings"
"github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/orchestrator"
"github.com/SAP/jenkins-library/pkg/piperutils"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
// GeneralConfigOptions contains all global configuration options for piper binary
type GeneralConfigOptions struct {
GitHubAccessTokens map[string]string // map of tokens with url as key in order to maintain url-specific tokens
CorrelationID string
CustomConfig string
GitHubTokens []string // list of entries in form of <server>:<token> to allow token authentication for downloading config / defaults
DefaultConfig []string //ordered list of Piper default configurations. Can be filePath or ENV containing JSON in format 'ENV:MY_ENV_VAR'
IgnoreCustomDefaults bool
ParametersJSON string
EnvRootPath string
NoTelemetry bool
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
LogFormat string
VaultRoleID string
VaultRoleSecretID string
VaultToken string
VaultServerURL string
VaultNamespace string
VaultPath string
HookConfig HookConfiguration
MetaDataResolver func() map[string]config.StepData
GCPJsonKeyFilePath string
GCSFolderPath string
GCSBucketId string
GCSSubFolder string
}
// HookConfiguration contains the configuration for supported hooks, so far Sentry and Splunk are supported.
type HookConfiguration struct {
SentryConfig SentryConfiguration `json:"sentry,omitempty"`
SplunkConfig SplunkConfiguration `json:"splunk,omitempty"`
}
// SentryConfiguration defines the configuration options for the Sentry logging system
type SentryConfiguration struct {
Dsn string `json:"dsn,omitempty"`
}
// SplunkConfiguration defines the configuration options for the Splunk logging system
type SplunkConfiguration struct {
Dsn string `json:"dsn,omitempty"`
Token string `json:"token,omitempty"`
Index string `json:"index,omitempty"`
SendLogs bool `json:"sendLogs"`
}
var rootCmd = &cobra.Command{
Use: "piper",
Short: "Executes CI/CD steps from project 'Piper' ",
Long: `
This project 'Piper' binary provides a CI/CD step library.
It contains many steps which can be used within CI/CD systems as well as directly on e.g. a developer's machine.
`,
}
// GeneralConfig contains global configuration flags for piper binary
var GeneralConfig GeneralConfigOptions
// Execute is the starting point of the piper command line tool
func Execute() {
rootCmd.AddCommand(ArtifactPrepareVersionCommand())
rootCmd.AddCommand(ConfigCommand())
rootCmd.AddCommand(DefaultsCommand())
rootCmd.AddCommand(ContainerSaveImageCommand())
rootCmd.AddCommand(CommandLineCompletionCommand())
rootCmd.AddCommand(VersionCommand())
rootCmd.AddCommand(DetectExecuteScanCommand())
rootCmd.AddCommand(HadolintExecuteCommand())
rootCmd.AddCommand(KarmaExecuteTestsCommand())
rootCmd.AddCommand(UiVeri5ExecuteTestsCommand())
rootCmd.AddCommand(SonarExecuteScanCommand())
rootCmd.AddCommand(KubernetesDeployCommand())
rootCmd.AddCommand(XsDeployCommand())
rootCmd.AddCommand(GithubCheckBranchProtectionCommand())
rootCmd.AddCommand(GithubCommentIssueCommand())
rootCmd.AddCommand(GithubCreateIssueCommand())
rootCmd.AddCommand(GithubCreatePullRequestCommand())
rootCmd.AddCommand(GithubPublishReleaseCommand())
rootCmd.AddCommand(GithubSetCommitStatusCommand())
rootCmd.AddCommand(GitopsUpdateDeploymentCommand())
rootCmd.AddCommand(CloudFoundryDeleteServiceCommand())
rootCmd.AddCommand(AbapEnvironmentPullGitRepoCommand())
rootCmd.AddCommand(AbapEnvironmentCloneGitRepoCommand())
rootCmd.AddCommand(AbapEnvironmentCheckoutBranchCommand())
rootCmd.AddCommand(AbapEnvironmentCreateSystemCommand())
rootCmd.AddCommand(CheckmarxExecuteScanCommand())
rootCmd.AddCommand(FortifyExecuteScanCommand())
rootCmd.AddCommand(MtaBuildCommand())
rootCmd.AddCommand(ProtecodeExecuteScanCommand())
rootCmd.AddCommand(MavenExecuteCommand())
rootCmd.AddCommand(CloudFoundryCreateServiceKeyCommand())
rootCmd.AddCommand(MavenBuildCommand())
rootCmd.AddCommand(MavenExecuteIntegrationCommand())
rootCmd.AddCommand(MavenExecuteStaticCodeChecksCommand())
rootCmd.AddCommand(NexusUploadCommand())
rootCmd.AddCommand(AbapEnvironmentPushATCSystemConfigCommand())
rootCmd.AddCommand(AbapEnvironmentRunATCCheckCommand())
rootCmd.AddCommand(NpmExecuteScriptsCommand())
rootCmd.AddCommand(NpmExecuteLintCommand())
rootCmd.AddCommand(GctsCreateRepositoryCommand())
rootCmd.AddCommand(GctsExecuteABAPUnitTestsCommand())
rootCmd.AddCommand(GctsDeployCommand())
rootCmd.AddCommand(MalwareExecuteScanCommand())
rootCmd.AddCommand(CloudFoundryCreateServiceCommand())
rootCmd.AddCommand(CloudFoundryDeployCommand())
rootCmd.AddCommand(GctsRollbackCommand())
rootCmd.AddCommand(WhitesourceExecuteScanCommand())
rootCmd.AddCommand(GctsCloneRepositoryCommand())
rootCmd.AddCommand(JsonApplyPatchCommand())
rootCmd.AddCommand(KanikoExecuteCommand())
rootCmd.AddCommand(CnbBuildCommand())
rootCmd.AddCommand(AbapEnvironmentBuildCommand())
rootCmd.AddCommand(AbapEnvironmentAssemblePackagesCommand())
rootCmd.AddCommand(AbapAddonAssemblyKitCheckCVsCommand())
rootCmd.AddCommand(AbapAddonAssemblyKitCheckPVCommand())
rootCmd.AddCommand(AbapAddonAssemblyKitCreateTargetVectorCommand())
rootCmd.AddCommand(AbapAddonAssemblyKitPublishTargetVectorCommand())
rootCmd.AddCommand(AbapAddonAssemblyKitRegisterPackagesCommand())
rootCmd.AddCommand(AbapAddonAssemblyKitReleasePackagesCommand())
rootCmd.AddCommand(AbapAddonAssemblyKitReserveNextPackagesCommand())
rootCmd.AddCommand(CloudFoundryCreateSpaceCommand())
rootCmd.AddCommand(CloudFoundryDeleteSpaceCommand())
rootCmd.AddCommand(VaultRotateSecretIdCommand())
rootCmd.AddCommand(IsChangeInDevelopmentCommand())
rootCmd.AddCommand(TransportRequestUploadCTSCommand())
rootCmd.AddCommand(TransportRequestUploadRFCCommand())
rootCmd.AddCommand(NewmanExecuteCommand())
rootCmd.AddCommand(IntegrationArtifactDeployCommand())
rootCmd.AddCommand(TransportRequestUploadSOLMANCommand())
rootCmd.AddCommand(IntegrationArtifactUpdateConfigurationCommand())
rootCmd.AddCommand(IntegrationArtifactGetMplStatusCommand())
rootCmd.AddCommand(IntegrationArtifactGetServiceEndpointCommand())
rootCmd.AddCommand(IntegrationArtifactDownloadCommand())
rootCmd.AddCommand(AbapEnvironmentAssembleConfirmCommand())
rootCmd.AddCommand(IntegrationArtifactUploadCommand())
rootCmd.AddCommand(IntegrationArtifactTriggerIntegrationTestCommand())
rootCmd.AddCommand(IntegrationArtifactUnDeployCommand())
rootCmd.AddCommand(IntegrationArtifactResourceCommand())
rootCmd.AddCommand(TerraformExecuteCommand())
rootCmd.AddCommand(ContainerExecuteStructureTestsCommand())
rootCmd.AddCommand(GaugeExecuteTestsCommand())
rootCmd.AddCommand(BatsExecuteTestsCommand())
rootCmd.AddCommand(PipelineCreateScanSummaryCommand())
rootCmd.AddCommand(TransportRequestDocIDFromGitCommand())
rootCmd.AddCommand(TransportRequestReqIDFromGitCommand())
rootCmd.AddCommand(WritePipelineEnv())
rootCmd.AddCommand(ReadPipelineEnv())
rootCmd.AddCommand(InfluxWriteDataCommand())
rootCmd.AddCommand(AbapEnvironmentRunAUnitTestCommand())
rootCmd.AddCommand(CheckStepActiveCommand())
rootCmd.AddCommand(GolangBuildCommand())
rootCmd.AddCommand(ShellExecuteCommand())
rootCmd.AddCommand(ApiProxyDownloadCommand())
rootCmd.AddCommand(ApiKeyValueMapDownloadCommand())
rootCmd.AddCommand(ApiProxyUploadCommand())
rootCmd.AddCommand(GradleExecuteBuildCommand())
addRootFlags(rootCmd)
if err := rootCmd.Execute(); err != nil {
log.SetErrorCategory(log.ErrorConfiguration)
log.Entry().WithError(err).Fatal("configuration error")
}
}
func addRootFlags(rootCmd *cobra.Command) {
var provider orchestrator.OrchestratorSpecificConfigProviding
var err error
provider, err = orchestrator.NewOrchestratorSpecificConfigProvider()
if err != nil {
log.Entry().Error(err)
provider = &orchestrator.UnknownOrchestratorConfigProvider{}
}
rootCmd.PersistentFlags().StringVar(&GeneralConfig.CorrelationID, "correlationID", provider.GetBuildUrl(), "ID for unique identification of a pipeline run")
rootCmd.PersistentFlags().StringVar(&GeneralConfig.CustomConfig, "customConfig", ".pipeline/config.yml", "Path to the pipeline configuration file")
rootCmd.PersistentFlags().StringSliceVar(&GeneralConfig.GitHubTokens, "gitHubTokens", AccessTokensFromEnvJSON(os.Getenv("PIPER_gitHubTokens")), "List of entries in form of <hostname>:<token> to allow GitHub token authentication for downloading config / defaults")
rootCmd.PersistentFlags().StringSliceVar(&GeneralConfig.DefaultConfig, "defaultConfig", []string{".pipeline/defaults.yaml"}, "Default configurations, passed as path to yaml file")
rootCmd.PersistentFlags().BoolVar(&GeneralConfig.IgnoreCustomDefaults, "ignoreCustomDefaults", false, "Disables evaluation of the parameter 'customDefaults' in the pipeline configuration file")
rootCmd.PersistentFlags().StringVar(&GeneralConfig.ParametersJSON, "parametersJSON", os.Getenv("PIPER_parametersJSON"), "Parameters to be considered in JSON format")
rootCmd.PersistentFlags().StringVar(&GeneralConfig.EnvRootPath, "envRootPath", ".pipeline", "Root path to Piper pipeline shared environments")
rootCmd.PersistentFlags().StringVar(&GeneralConfig.StageName, "stageName", "", "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")
rootCmd.PersistentFlags().BoolVar(&GeneralConfig.NoTelemetry, "noTelemetry", false, "Disables telemetry reporting")
rootCmd.PersistentFlags().BoolVarP(&GeneralConfig.Verbose, "verbose", "v", false, "verbose output")
rootCmd.PersistentFlags().StringVar(&GeneralConfig.LogFormat, "logFormat", "default", "Log format to use. Options: default, timestamp, plain, full.")
rootCmd.PersistentFlags().StringVar(&GeneralConfig.VaultServerURL, "vaultServerUrl", "", "The Vault server which should be used to fetch credentials")
rootCmd.PersistentFlags().StringVar(&GeneralConfig.VaultNamespace, "vaultNamespace", "", "The Vault namespace which should be used to fetch credentials")
rootCmd.PersistentFlags().StringVar(&GeneralConfig.VaultPath, "vaultPath", "", "The path which should be used to fetch credentials")
rootCmd.PersistentFlags().StringVar(&GeneralConfig.GCPJsonKeyFilePath, "gcpJsonKeyFilePath", "", "File path to Google Cloud Platform JSON key file")
rootCmd.PersistentFlags().StringVar(&GeneralConfig.GCSFolderPath, "gcsFolderPath", "", "GCS folder path. One of the components of GCS target folder")
rootCmd.PersistentFlags().StringVar(&GeneralConfig.GCSBucketId, "gcsBucketId", "", "Bucket name for Google Cloud Storage")
rootCmd.PersistentFlags().StringVar(&GeneralConfig.GCSSubFolder, "gcsSubFolder", "", "Used to logically separate results of the same step result type")
}
// ResolveAccessTokens reads a list of tokens in format host:token passed via command line
// and transfers this into a map as a more consumable format.
func ResolveAccessTokens(tokenList []string) map[string]string {
tokenMap := map[string]string{}
for _, tokenEntry := range tokenList {
log.Entry().Debugf("processing token %v", tokenEntry)
parts := strings.Split(tokenEntry, ":")
if len(parts) != 2 {
log.Entry().Warningf("wrong format for access token %v", tokenEntry)
} else {
tokenMap[parts[0]] = parts[1]
}
}
return tokenMap
}
// AccessTokensFromEnvJSON resolves access tokens when passed as JSON in an environment variable
func AccessTokensFromEnvJSON(env string) []string {
accessTokens := []string{}
if len(env) == 0 {
return accessTokens
}
err := json.Unmarshal([]byte(env), &accessTokens)
if err != nil {
log.Entry().Infof("Token json '%v' has wrong format.", env)
}
return accessTokens
}
// initStageName initializes GeneralConfig.StageName from either GeneralConfig.ParametersJSON
// or the environment variable (orchestrator specific), unless it has been provided as command line option.
// Log output needs to be suppressed via outputToLog by the getConfig step.
func initStageName(outputToLog bool) {
var stageNameSource string
if outputToLog {
defer func() {
log.Entry().Infof("Using stageName '%s' from %s", GeneralConfig.StageName, stageNameSource)
}()
}
if GeneralConfig.StageName != "" {
// Means it was given as command line argument and has the highest precedence
stageNameSource = "command line arguments"
return
}
// Use stageName from ENV as fall-back, for when extracting it from parametersJSON fails below
provider, err := orchestrator.NewOrchestratorSpecificConfigProvider()
if err != nil {
log.Entry().WithError(err).Warning("Cannot infer stage name from CI environment")
} else {
stageNameSource = "env variable"
GeneralConfig.StageName = provider.GetStageName()
}
if len(GeneralConfig.ParametersJSON) == 0 {
return
}
var params map[string]interface{}
err = json.Unmarshal([]byte(GeneralConfig.ParametersJSON), &params)
if err != nil {
if outputToLog {
log.Entry().Infof("Failed to extract 'stageName' from parametersJSON: %v", err)
}
return
}
stageName, hasKey := params["stageName"]
if !hasKey {
return
}
if stageNameString, ok := stageName.(string); ok && stageNameString != "" {
stageNameSource = "parametersJSON"
GeneralConfig.StageName = stageNameString
}
}
// 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, t map[string]string) (io.ReadCloser, error)) error {
log.SetFormatter(GeneralConfig.LogFormat)
initStageName(true)
filters := metadata.GetParameterFilters()
// 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")
envParams := metadata.GetResourceParameters(GeneralConfig.EnvRootPath, "commonPipelineEnvironment")
reportingEnvParams := config.ReportingParameters.GetResourceParameters(GeneralConfig.EnvRootPath, "commonPipelineEnvironment")
resourceParams := mergeResourceParameters(envParams, reportingEnvParams)
flagValues := config.AvailableFlagValues(cmd, &filters)
var myConfig config.Config
var stepConfig config.StepConfig
// add vault credentials so that configuration can be fetched from vault
if GeneralConfig.VaultRoleID == "" {
GeneralConfig.VaultRoleID = os.Getenv("PIPER_vaultAppRoleID")
}
if GeneralConfig.VaultRoleSecretID == "" {
GeneralConfig.VaultRoleSecretID = os.Getenv("PIPER_vaultAppRoleSecretID")
}
if GeneralConfig.VaultToken == "" {
GeneralConfig.VaultToken = os.Getenv("PIPER_vaultToken")
}
myConfig.SetVaultCredentials(GeneralConfig.VaultRoleID, GeneralConfig.VaultRoleSecretID, GeneralConfig.VaultToken)
if len(GeneralConfig.StepConfigJSON) != 0 {
// ignore config & defaults in favor of passed stepConfigJSON
stepConfig = config.GetStepConfigWithJSON(flagValues, GeneralConfig.StepConfigJSON, filters)
log.Entry().Infof("Project config: passed via JSON")
log.Entry().Infof("Project defaults: passed via JSON")
} else {
// use config & defaults
var customConfig io.ReadCloser
var err error
//accept that config file and defaults cannot be loaded since both are not mandatory here
{
projectConfigFile := getProjectConfigFile(GeneralConfig.CustomConfig)
if exists, err := piperutils.FileExists(projectConfigFile); exists {
log.Entry().Infof("Project config: '%s'", projectConfigFile)
if customConfig, err = openFile(projectConfigFile, GeneralConfig.GitHubAccessTokens); err != nil {
return errors.Wrapf(err, "Cannot read '%s'", projectConfigFile)
}
} else {
log.Entry().Infof("Project config: NONE ('%s' does not exist)", projectConfigFile)
customConfig = nil
}
}
var defaultConfig []io.ReadCloser
if len(GeneralConfig.DefaultConfig) == 0 {
log.Entry().Info("Project defaults: NONE")
}
for _, projectDefaultFile := range GeneralConfig.DefaultConfig {
fc, err := openFile(projectDefaultFile, GeneralConfig.GitHubAccessTokens)
// only create error for non-default values
if err != nil {
if projectDefaultFile != ".pipeline/defaults.yaml" {
log.Entry().Infof("Project defaults: '%s'", projectDefaultFile)
return errors.Wrapf(err, "Cannot read '%s'", projectDefaultFile)
}
} else {
log.Entry().Infof("Project defaults: '%s'", projectDefaultFile)
defaultConfig = append(defaultConfig, fc)
}
}
stepConfig, err = myConfig.GetStepConfig(flagValues, GeneralConfig.ParametersJSON, customConfig, defaultConfig, GeneralConfig.IgnoreCustomDefaults, filters, *metadata, resourceParams, GeneralConfig.StageName, stepName)
if verbose, ok := stepConfig.Config["verbose"].(bool); ok && verbose {
log.SetVerbose(verbose)
GeneralConfig.Verbose = verbose
} else if !ok && stepConfig.Config["verbose"] != nil {
log.Entry().Warnf("invalid value for parameter verbose: '%v'", stepConfig.Config["verbose"])
}
if err != nil {
return errors.Wrap(err, "retrieving step configuration failed")
}
}
if fmt.Sprintf("%v", stepConfig.Config["collectTelemetryData"]) == "false" {
GeneralConfig.NoTelemetry = true
}
stepConfig.Config = checkTypes(stepConfig.Config, options)
confJSON, _ := json.Marshal(stepConfig.Config)
_ = json.Unmarshal(confJSON, &options)
config.MarkFlagsWithValue(cmd, stepConfig)
retrieveHookConfig(stepConfig.HookConfig, &GeneralConfig.HookConfig)
if GeneralConfig.GCPJsonKeyFilePath == "" {
GeneralConfig.GCPJsonKeyFilePath, _ = stepConfig.Config["gcpJsonKeyFilePath"].(string)
}
if GeneralConfig.GCSFolderPath == "" {
GeneralConfig.GCSFolderPath, _ = stepConfig.Config["gcsFolderPath"].(string)
}
if GeneralConfig.GCSBucketId == "" {
GeneralConfig.GCSBucketId, _ = stepConfig.Config["gcsBucketId"].(string)
}
if GeneralConfig.GCSSubFolder == "" {
GeneralConfig.GCSSubFolder, _ = stepConfig.Config["gcsSubFolder"].(string)
}
return nil
}
func retrieveHookConfig(source map[string]interface{}, target *HookConfiguration) {
if source != nil {
log.Entry().Info("Retrieving hook configuration")
b, err := json.Marshal(source)
if err != nil {
log.Entry().Warningf("Failed to marshal source hook configuration: %v", err)
}
err = json.Unmarshal(b, target)
if err != nil {
log.Entry().Warningf("Failed to retrieve hook configuration: %v", err)
}
}
}
var errIncompatibleTypes = fmt.Errorf("incompatible types")
func checkTypes(config map[string]interface{}, options interface{}) map[string]interface{} {
optionsType := getStepOptionsStructType(options)
for paramName := range config {
optionsField := findStructFieldByJSONTag(paramName, optionsType)
if optionsField == nil {
continue
}
if config[paramName] == nil {
// There is a key, but no value. This can result from merging values from the CPE.
continue
}
paramValueType := reflect.ValueOf(config[paramName])
if optionsField.Type.Kind() == paramValueType.Kind() {
// Types already match, nothing to do
continue
}
var typeError error = nil
switch paramValueType.Kind() {
case reflect.String:
typeError = convertValueFromString(config, optionsField, paramName, paramValueType.String())
case reflect.Float32, reflect.Float64:
typeError = convertValueFromFloat(config, optionsField, paramName, paramValueType.Float())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
typeError = convertValueFromInt(config, optionsField, paramName, paramValueType.Int())
default:
log.Entry().Warnf("Config value for '%s' is of unexpected type %s, expected %s. "+
"The value may be ignored as a result. To avoid any risk, specify this value with explicit type.",
paramName, paramValueType.Kind(), optionsField.Type.Kind())
}
if typeError != nil {
typeError = fmt.Errorf("config value for '%s' is of unexpected type %s, expected %s: %w",
paramName, paramValueType.Kind(), optionsField.Type.Kind(), typeError)
log.SetErrorCategory(log.ErrorConfiguration)
log.Entry().WithError(typeError).Fatal("type error in configuration")
}
}
return config
}
func convertValueFromString(config map[string]interface{}, optionsField *reflect.StructField, paramName, paramValue string) error {
switch optionsField.Type.Kind() {
case reflect.Slice, reflect.Array:
// Could do automatic conversion for those types in theory,
// but that might obscure what really happens in error cases.
return fmt.Errorf("expected type to be a list (or slice, or array) but got string")
case reflect.Bool:
// Sensible to convert strings "true"/"false" to respective boolean values as it is
// common practice to write booleans as string in yaml files.
paramValue = strings.ToLower(paramValue)
if paramValue == "true" {
config[paramName] = true
return nil
} else if paramValue == "false" {
config[paramName] = false
return nil
}
}
return errIncompatibleTypes
}
func convertValueFromFloat(config map[string]interface{}, optionsField *reflect.StructField, paramName string, paramValue float64) error {
switch optionsField.Type.Kind() {
case reflect.String:
val := strconv.FormatFloat(paramValue, 'f', -1, 64)
// if Sprinted value and val are equal, we can be pretty sure that the result fits
// for very large numbers for example an exponential format is printed
if val == fmt.Sprint(paramValue) {
config[paramName] = val
return nil
}
// allow float numbers containing a decimal separator
if strings.Contains(val, ".") {
config[paramName] = val
return nil
}
// if now no decimal separator is available we cannot be sure that the result is correct:
// long numbers like e.g. 73554900100200011600 will not be represented correctly after reading the yaml
// thus we cannot assume that the string is correct.
// short numbers will be handled as int anyway
return errIncompatibleTypes
case reflect.Float32:
config[paramName] = float32(paramValue)
return nil
case reflect.Float64:
config[paramName] = paramValue
return nil
case reflect.Int:
// Treat as type-mismatch only in case the conversion would be lossy.
// In that case, the json.Unmarshall() would indeed just drop it, so we want to fail.
if float64(int(paramValue)) == paramValue {
config[paramName] = int(paramValue)
return nil
}
}
return errIncompatibleTypes
}
func convertValueFromInt(config map[string]interface{}, optionsField *reflect.StructField, paramName string, paramValue int64) error {
switch optionsField.Type.Kind() {
case reflect.String:
config[paramName] = strconv.FormatInt(paramValue, 10)
return nil
case reflect.Float32:
config[paramName] = float32(paramValue)
return nil
case reflect.Float64:
config[paramName] = float64(paramValue)
return nil
}
return errIncompatibleTypes
}
func findStructFieldByJSONTag(tagName string, optionsType reflect.Type) *reflect.StructField {
for i := 0; i < optionsType.NumField(); i++ {
field := optionsType.Field(i)
tag := field.Tag.Get("json")
if tagName == tag || tagName+",omitempty" == tag {
return &field
}
}
return nil
}
func getStepOptionsStructType(stepOptions interface{}) reflect.Type {
typedOptions := reflect.ValueOf(stepOptions)
if typedOptions.Kind() == reflect.Ptr {
typedOptions = typedOptions.Elem()
}
return typedOptions.Type()
}
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
}
func mergeResourceParameters(resParams ...map[string]interface{}) map[string]interface{} {
result := make(map[string]interface{})
for _, m := range resParams {
for k, v := range m {
result[k] = v
}
}
return result
}