1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-01-08 04:21:26 +02:00

Persisted pipeline environment for golang library (#1091)

* Use commonPipelineEnvironment in go binary

* Update groovy part incl. tests

* Rework structure and naming

* Support influx resources in steps

* Update tests and some cleanups

* Add correct defer handling

* Address PR feedback

* Fix test

* Update resources.go

Co-authored-by: Sven Merk <33895725+nevskrem@users.noreply.github.com>
This commit is contained in:
Oliver Nocon 2020-01-15 12:16:25 +01:00 committed by GitHub
parent e5db600cf4
commit a46b57e6b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 1369 additions and 468 deletions

View File

@ -4,6 +4,7 @@
1. [Getting started](#getting-started) 1. [Getting started](#getting-started)
1. [Build the project](#build-the-project_) 1. [Build the project](#build-the-project_)
1. [Generating step framework](#generating-step-framework)
1. [Logging](#logging) 1. [Logging](#logging)
1. [Error handling](#error-handling) 1. [Error handling](#error-handling)

View File

@ -5,6 +5,7 @@ import (
"github.com/SAP/jenkins-library/pkg/config" "github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -20,11 +21,11 @@ type detectExecuteScanOptions struct {
} }
var myDetectExecuteScanOptions detectExecuteScanOptions var myDetectExecuteScanOptions detectExecuteScanOptions
var detectExecuteScanStepConfigJSON string
// DetectExecuteScanCommand Executes Synopsis Detect scan // DetectExecuteScanCommand Executes Synopsis Detect scan
func DetectExecuteScanCommand() *cobra.Command { func DetectExecuteScanCommand() *cobra.Command {
metadata := detectExecuteScanMetadata() metadata := detectExecuteScanMetadata()
var createDetectExecuteScanCmd = &cobra.Command{ var createDetectExecuteScanCmd = &cobra.Command{
Use: "detectExecuteScan", Use: "detectExecuteScan",
Short: "Executes Synopsis Detect scan", Short: "Executes Synopsis Detect scan",
@ -35,6 +36,7 @@ func DetectExecuteScanCommand() *cobra.Command {
return PrepareConfig(cmd, &metadata, "detectExecuteScan", &myDetectExecuteScanOptions, config.OpenPiperFile) return PrepareConfig(cmd, &metadata, "detectExecuteScan", &myDetectExecuteScanOptions, config.OpenPiperFile)
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return detectExecuteScan(myDetectExecuteScanOptions) return detectExecuteScan(myDetectExecuteScanOptions)
}, },
} }
@ -66,6 +68,7 @@ func detectExecuteScanMetadata() config.StepData {
Parameters: []config.StepParameters{ Parameters: []config.StepParameters{
{ {
Name: "apiToken", Name: "apiToken",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -73,6 +76,7 @@ func detectExecuteScanMetadata() config.StepData {
}, },
{ {
Name: "codeLocation", Name: "codeLocation",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: false, Mandatory: false,
@ -80,6 +84,7 @@ func detectExecuteScanMetadata() config.StepData {
}, },
{ {
Name: "projectName", Name: "projectName",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -87,6 +92,7 @@ func detectExecuteScanMetadata() config.StepData {
}, },
{ {
Name: "projectVersion", Name: "projectVersion",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -94,6 +100,7 @@ func detectExecuteScanMetadata() config.StepData {
}, },
{ {
Name: "scanners", Name: "scanners",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "[]string", Type: "[]string",
Mandatory: false, Mandatory: false,
@ -101,6 +108,7 @@ func detectExecuteScanMetadata() config.StepData {
}, },
{ {
Name: "scanPaths", Name: "scanPaths",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "[]string", Type: "[]string",
Mandatory: false, Mandatory: false,
@ -108,6 +116,7 @@ func detectExecuteScanMetadata() config.StepData {
}, },
{ {
Name: "scanProperties", Name: "scanProperties",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "[]string", Type: "[]string",
Mandatory: false, Mandatory: false,
@ -115,6 +124,7 @@ func detectExecuteScanMetadata() config.StepData {
}, },
{ {
Name: "serverUrl", Name: "serverUrl",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: false, Mandatory: false,

View File

@ -54,6 +54,8 @@ func generateConfig() error {
return errors.Wrap(err, "metadata: read failed") return errors.Wrap(err, "metadata: read failed")
} }
resourceParams := metadata.GetResourceParameters(GeneralConfig.EnvRootPath, "commonPipelineEnvironment")
var customConfig io.ReadCloser var customConfig io.ReadCloser
{ {
exists, e := piperutils.FileExists(GeneralConfig.CustomConfig) exists, e := piperutils.FileExists(GeneralConfig.CustomConfig)
@ -91,7 +93,7 @@ func generateConfig() error {
params = metadata.Spec.Inputs.Parameters params = metadata.Spec.Inputs.Parameters
} }
stepConfig, err = myConfig.GetStepConfig(flags, GeneralConfig.ParametersJSON, customConfig, defaultConfig, paramFilter, params, GeneralConfig.StageName, metadata.Metadata.Name) stepConfig, err = myConfig.GetStepConfig(flags, GeneralConfig.ParametersJSON, customConfig, defaultConfig, paramFilter, params, resourceParams, GeneralConfig.StageName, metadata.Metadata.Name)
if err != nil { if err != nil {
return errors.Wrap(err, "getting step config failed") return errors.Wrap(err, "getting step config failed")
} }

View File

@ -5,6 +5,7 @@ import (
"github.com/SAP/jenkins-library/pkg/config" "github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -23,11 +24,11 @@ type githubCreatePullRequestOptions struct {
} }
var myGithubCreatePullRequestOptions githubCreatePullRequestOptions var myGithubCreatePullRequestOptions githubCreatePullRequestOptions
var githubCreatePullRequestStepConfigJSON string
// GithubCreatePullRequestCommand Create a pull request on GitHub // GithubCreatePullRequestCommand Create a pull request on GitHub
func GithubCreatePullRequestCommand() *cobra.Command { func GithubCreatePullRequestCommand() *cobra.Command {
metadata := githubCreatePullRequestMetadata() metadata := githubCreatePullRequestMetadata()
var createGithubCreatePullRequestCmd = &cobra.Command{ var createGithubCreatePullRequestCmd = &cobra.Command{
Use: "githubCreatePullRequest", Use: "githubCreatePullRequest",
Short: "Create a pull request on GitHub", Short: "Create a pull request on GitHub",
@ -40,6 +41,7 @@ It can for example be used for GitOps scenarios or for scenarios where you want
return PrepareConfig(cmd, &metadata, "githubCreatePullRequest", &myGithubCreatePullRequestOptions, config.OpenPiperFile) return PrepareConfig(cmd, &metadata, "githubCreatePullRequest", &myGithubCreatePullRequestOptions, config.OpenPiperFile)
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return githubCreatePullRequest(myGithubCreatePullRequestOptions) return githubCreatePullRequest(myGithubCreatePullRequestOptions)
}, },
} }
@ -80,6 +82,7 @@ func githubCreatePullRequestMetadata() config.StepData {
Parameters: []config.StepParameters{ Parameters: []config.StepParameters{
{ {
Name: "assignees", Name: "assignees",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "[]string", Type: "[]string",
Mandatory: false, Mandatory: false,
@ -87,6 +90,7 @@ func githubCreatePullRequestMetadata() config.StepData {
}, },
{ {
Name: "base", Name: "base",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -94,6 +98,7 @@ func githubCreatePullRequestMetadata() config.StepData {
}, },
{ {
Name: "body", Name: "body",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -101,6 +106,7 @@ func githubCreatePullRequestMetadata() config.StepData {
}, },
{ {
Name: "apiUrl", Name: "apiUrl",
ResourceRef: []config.ResourceReference{},
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -108,6 +114,7 @@ func githubCreatePullRequestMetadata() config.StepData {
}, },
{ {
Name: "head", Name: "head",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -115,6 +122,7 @@ func githubCreatePullRequestMetadata() config.StepData {
}, },
{ {
Name: "owner", Name: "owner",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -122,6 +130,7 @@ func githubCreatePullRequestMetadata() config.StepData {
}, },
{ {
Name: "repository", Name: "repository",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -129,6 +138,7 @@ func githubCreatePullRequestMetadata() config.StepData {
}, },
{ {
Name: "serverUrl", Name: "serverUrl",
ResourceRef: []config.ResourceReference{},
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -136,6 +146,7 @@ func githubCreatePullRequestMetadata() config.StepData {
}, },
{ {
Name: "title", Name: "title",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -143,6 +154,7 @@ func githubCreatePullRequestMetadata() config.StepData {
}, },
{ {
Name: "token", Name: "token",
ResourceRef: []config.ResourceReference{},
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -150,6 +162,7 @@ func githubCreatePullRequestMetadata() config.StepData {
}, },
{ {
Name: "labels", Name: "labels",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "[]string", Type: "[]string",
Mandatory: false, Mandatory: false,

View File

@ -5,32 +5,33 @@ import (
"github.com/SAP/jenkins-library/pkg/config" "github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
type githubPublishReleaseOptions struct { type githubPublishReleaseOptions struct {
AddClosedIssues bool `json:"addClosedIssues,omitempty"` AddClosedIssues bool `json:"addClosedIssues,omitempty"`
AddDeltaToLastRelease bool `json:"addDeltaToLastRelease,omitempty"` AddDeltaToLastRelease bool `json:"addDeltaToLastRelease,omitempty"`
APIURL string `json:"apiUrl,omitempty"`
AssetPath string `json:"assetPath,omitempty"` AssetPath string `json:"assetPath,omitempty"`
Commitish string `json:"commitish,omitempty"` Commitish string `json:"commitish,omitempty"`
ExcludeLabels []string `json:"excludeLabels,omitempty"` ExcludeLabels []string `json:"excludeLabels,omitempty"`
APIURL string `json:"apiUrl,omitempty"` Labels []string `json:"labels,omitempty"`
Owner string `json:"owner,omitempty"` Owner string `json:"owner,omitempty"`
ReleaseBodyHeader string `json:"releaseBodyHeader,omitempty"`
Repository string `json:"repository,omitempty"` Repository string `json:"repository,omitempty"`
ServerURL string `json:"serverUrl,omitempty"` ServerURL string `json:"serverUrl,omitempty"`
Token string `json:"token,omitempty"` Token string `json:"token,omitempty"`
UploadURL string `json:"uploadUrl,omitempty"` UploadURL string `json:"uploadUrl,omitempty"`
Labels []string `json:"labels,omitempty"`
ReleaseBodyHeader string `json:"releaseBodyHeader,omitempty"`
Version string `json:"version,omitempty"` Version string `json:"version,omitempty"`
} }
var myGithubPublishReleaseOptions githubPublishReleaseOptions var myGithubPublishReleaseOptions githubPublishReleaseOptions
var githubPublishReleaseStepConfigJSON string
// GithubPublishReleaseCommand Publish a release in GitHub // GithubPublishReleaseCommand Publish a release in GitHub
func GithubPublishReleaseCommand() *cobra.Command { func GithubPublishReleaseCommand() *cobra.Command {
metadata := githubPublishReleaseMetadata() metadata := githubPublishReleaseMetadata()
var createGithubPublishReleaseCmd = &cobra.Command{ var createGithubPublishReleaseCmd = &cobra.Command{
Use: "githubPublishRelease", Use: "githubPublishRelease",
Short: "Publish a release in GitHub", Short: "Publish a release in GitHub",
@ -50,6 +51,7 @@ The result looks like
return PrepareConfig(cmd, &metadata, "githubPublishRelease", &myGithubPublishReleaseOptions, config.OpenPiperFile) return PrepareConfig(cmd, &metadata, "githubPublishRelease", &myGithubPublishReleaseOptions, config.OpenPiperFile)
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return githubPublishRelease(myGithubPublishReleaseOptions) return githubPublishRelease(myGithubPublishReleaseOptions)
}, },
} }
@ -61,17 +63,17 @@ The result looks like
func addGithubPublishReleaseFlags(cmd *cobra.Command) { func addGithubPublishReleaseFlags(cmd *cobra.Command) {
cmd.Flags().BoolVar(&myGithubPublishReleaseOptions.AddClosedIssues, "addClosedIssues", false, "If set to `true`, closed issues and merged pull-requests since the last release will added below the `releaseBodyHeader`") cmd.Flags().BoolVar(&myGithubPublishReleaseOptions.AddClosedIssues, "addClosedIssues", false, "If set to `true`, closed issues and merged pull-requests since the last release will added below the `releaseBodyHeader`")
cmd.Flags().BoolVar(&myGithubPublishReleaseOptions.AddDeltaToLastRelease, "addDeltaToLastRelease", false, "If set to `true`, a link will be added to the relese information that brings up all commits since the last release.") cmd.Flags().BoolVar(&myGithubPublishReleaseOptions.AddDeltaToLastRelease, "addDeltaToLastRelease", false, "If set to `true`, a link will be added to the relese information that brings up all commits since the last release.")
cmd.Flags().StringVar(&myGithubPublishReleaseOptions.APIURL, "apiUrl", "https://api.github.com", "Set the GitHub API url.")
cmd.Flags().StringVar(&myGithubPublishReleaseOptions.AssetPath, "assetPath", os.Getenv("PIPER_assetPath"), "Path to a release asset which should be uploaded to the list of release assets.") cmd.Flags().StringVar(&myGithubPublishReleaseOptions.AssetPath, "assetPath", os.Getenv("PIPER_assetPath"), "Path to a release asset which should be uploaded to the list of release assets.")
cmd.Flags().StringVar(&myGithubPublishReleaseOptions.Commitish, "commitish", "master", "Target git commitish for the release") cmd.Flags().StringVar(&myGithubPublishReleaseOptions.Commitish, "commitish", "master", "Target git commitish for the release")
cmd.Flags().StringSliceVar(&myGithubPublishReleaseOptions.ExcludeLabels, "excludeLabels", []string{}, "Allows to exclude issues with dedicated list of labels.") cmd.Flags().StringSliceVar(&myGithubPublishReleaseOptions.ExcludeLabels, "excludeLabels", []string{}, "Allows to exclude issues with dedicated list of labels.")
cmd.Flags().StringVar(&myGithubPublishReleaseOptions.APIURL, "apiUrl", "https://api.github.com", "Set the GitHub API url.") cmd.Flags().StringSliceVar(&myGithubPublishReleaseOptions.Labels, "labels", []string{}, "Labels to include in issue search.")
cmd.Flags().StringVar(&myGithubPublishReleaseOptions.Owner, "owner", os.Getenv("PIPER_owner"), "Set the GitHub organization.") cmd.Flags().StringVar(&myGithubPublishReleaseOptions.Owner, "owner", os.Getenv("PIPER_owner"), "Set the GitHub organization.")
cmd.Flags().StringVar(&myGithubPublishReleaseOptions.ReleaseBodyHeader, "releaseBodyHeader", os.Getenv("PIPER_releaseBodyHeader"), "Content which will appear for the release.")
cmd.Flags().StringVar(&myGithubPublishReleaseOptions.Repository, "repository", os.Getenv("PIPER_repository"), "Set the GitHub repository.") cmd.Flags().StringVar(&myGithubPublishReleaseOptions.Repository, "repository", os.Getenv("PIPER_repository"), "Set the GitHub repository.")
cmd.Flags().StringVar(&myGithubPublishReleaseOptions.ServerURL, "serverUrl", "https://github.com", "GitHub server url for end-user access.") cmd.Flags().StringVar(&myGithubPublishReleaseOptions.ServerURL, "serverUrl", "https://github.com", "GitHub server url for end-user access.")
cmd.Flags().StringVar(&myGithubPublishReleaseOptions.Token, "token", os.Getenv("PIPER_token"), "GitHub personal access token as per https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line") cmd.Flags().StringVar(&myGithubPublishReleaseOptions.Token, "token", os.Getenv("PIPER_token"), "GitHub personal access token as per https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line")
cmd.Flags().StringVar(&myGithubPublishReleaseOptions.UploadURL, "uploadUrl", "https://uploads.github.com", "Set the GitHub API url.") cmd.Flags().StringVar(&myGithubPublishReleaseOptions.UploadURL, "uploadUrl", "https://uploads.github.com", "Set the GitHub API url.")
cmd.Flags().StringSliceVar(&myGithubPublishReleaseOptions.Labels, "labels", []string{}, "Labels to include in issue search.")
cmd.Flags().StringVar(&myGithubPublishReleaseOptions.ReleaseBodyHeader, "releaseBodyHeader", os.Getenv("PIPER_releaseBodyHeader"), "Content which will appear for the release.")
cmd.Flags().StringVar(&myGithubPublishReleaseOptions.Version, "version", os.Getenv("PIPER_version"), "Define the version number which will be written as tag as well as release name.") cmd.Flags().StringVar(&myGithubPublishReleaseOptions.Version, "version", os.Getenv("PIPER_version"), "Define the version number which will be written as tag as well as release name.")
cmd.MarkFlagRequired("apiUrl") cmd.MarkFlagRequired("apiUrl")
@ -91,6 +93,7 @@ func githubPublishReleaseMetadata() config.StepData {
Parameters: []config.StepParameters{ Parameters: []config.StepParameters{
{ {
Name: "addClosedIssues", Name: "addClosedIssues",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "bool", Type: "bool",
Mandatory: false, Mandatory: false,
@ -98,13 +101,23 @@ func githubPublishReleaseMetadata() config.StepData {
}, },
{ {
Name: "addDeltaToLastRelease", Name: "addDeltaToLastRelease",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "bool", Type: "bool",
Mandatory: false, Mandatory: false,
Aliases: []config.Alias{}, Aliases: []config.Alias{},
}, },
{
Name: "apiUrl",
ResourceRef: []config.ResourceReference{},
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: true,
Aliases: []config.Alias{{Name: "githubApiUrl"}},
},
{ {
Name: "assetPath", Name: "assetPath",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: false, Mandatory: false,
@ -112,6 +125,7 @@ func githubPublishReleaseMetadata() config.StepData {
}, },
{ {
Name: "commitish", Name: "commitish",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: false, Mandatory: false,
@ -119,27 +133,39 @@ func githubPublishReleaseMetadata() config.StepData {
}, },
{ {
Name: "excludeLabels", Name: "excludeLabels",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "[]string", Type: "[]string",
Mandatory: false, Mandatory: false,
Aliases: []config.Alias{}, Aliases: []config.Alias{},
}, },
{ {
Name: "apiUrl", Name: "labels",
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, ResourceRef: []config.ResourceReference{},
Type: "string", Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Mandatory: true, Type: "[]string",
Aliases: []config.Alias{{Name: "githubApiUrl"}}, Mandatory: false,
Aliases: []config.Alias{},
}, },
{ {
Name: "owner", Name: "owner",
ResourceRef: []config.ResourceReference{{Name: "commonPipelineEnvironment", Param: "github/owner"}},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
Aliases: []config.Alias{{Name: "githubOrg"}}, Aliases: []config.Alias{{Name: "githubOrg"}},
}, },
{
Name: "releaseBodyHeader",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
},
{ {
Name: "repository", Name: "repository",
ResourceRef: []config.ResourceReference{{Name: "commonPipelineEnvironment", Param: "github/repository"}},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -147,6 +173,7 @@ func githubPublishReleaseMetadata() config.StepData {
}, },
{ {
Name: "serverUrl", Name: "serverUrl",
ResourceRef: []config.ResourceReference{},
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -154,6 +181,7 @@ func githubPublishReleaseMetadata() config.StepData {
}, },
{ {
Name: "token", Name: "token",
ResourceRef: []config.ResourceReference{},
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -161,27 +189,15 @@ func githubPublishReleaseMetadata() config.StepData {
}, },
{ {
Name: "uploadUrl", Name: "uploadUrl",
ResourceRef: []config.ResourceReference{},
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
Aliases: []config.Alias{{Name: "githubUploadUrl"}}, Aliases: []config.Alias{{Name: "githubUploadUrl"}},
}, },
{
Name: "labels",
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "[]string",
Mandatory: false,
Aliases: []config.Alias{},
},
{
Name: "releaseBodyHeader",
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string",
Mandatory: false,
Aliases: []config.Alias{},
},
{ {
Name: "version", Name: "version",
ResourceRef: []config.ResourceReference{{Name: "commonPipelineEnvironment", Param: "artifactVersion"}},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,

View File

@ -3,6 +3,7 @@ package cmd
import ( import (
"github.com/SAP/jenkins-library/pkg/config" "github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -13,11 +14,11 @@ type karmaExecuteTestsOptions struct {
} }
var myKarmaExecuteTestsOptions karmaExecuteTestsOptions var myKarmaExecuteTestsOptions karmaExecuteTestsOptions
var karmaExecuteTestsStepConfigJSON string
// KarmaExecuteTestsCommand Executes the Karma test runner // KarmaExecuteTestsCommand Executes the Karma test runner
func KarmaExecuteTestsCommand() *cobra.Command { func KarmaExecuteTestsCommand() *cobra.Command {
metadata := karmaExecuteTestsMetadata() metadata := karmaExecuteTestsMetadata()
var createKarmaExecuteTestsCmd = &cobra.Command{ var createKarmaExecuteTestsCmd = &cobra.Command{
Use: "karmaExecuteTests", Use: "karmaExecuteTests",
Short: "Executes the Karma test runner", Short: "Executes the Karma test runner",
@ -38,6 +39,7 @@ In the Docker network, the containers can be referenced by the values provided i
return PrepareConfig(cmd, &metadata, "karmaExecuteTests", &myKarmaExecuteTestsOptions, config.OpenPiperFile) return PrepareConfig(cmd, &metadata, "karmaExecuteTests", &myKarmaExecuteTestsOptions, config.OpenPiperFile)
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return karmaExecuteTests(myKarmaExecuteTestsOptions) return karmaExecuteTests(myKarmaExecuteTestsOptions)
}, },
} }
@ -64,6 +66,7 @@ func karmaExecuteTestsMetadata() config.StepData {
Parameters: []config.StepParameters{ Parameters: []config.StepParameters{
{ {
Name: "installCommand", Name: "installCommand",
ResourceRef: []config.ResourceReference{},
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -71,6 +74,7 @@ func karmaExecuteTestsMetadata() config.StepData {
}, },
{ {
Name: "modulePath", Name: "modulePath",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -78,6 +82,7 @@ func karmaExecuteTestsMetadata() config.StepData {
}, },
{ {
Name: "runCommand", Name: "runCommand",
ResourceRef: []config.ResourceReference{},
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,

View File

@ -18,6 +18,7 @@ type GeneralConfigOptions struct {
CustomConfig string CustomConfig string
DefaultConfig []string //ordered list of Piper default configurations. Can be filePath or ENV containing JSON in format 'ENV:MY_ENV_VAR' DefaultConfig []string //ordered list of Piper default configurations. Can be filePath or ENV containing JSON in format 'ENV:MY_ENV_VAR'
ParametersJSON string ParametersJSON string
EnvRootPath string
StageName string StageName string
StepConfigJSON string StepConfigJSON string
StepMetadata string //metadata to be considered, can be filePath or ENV containing JSON in format 'ENV:MY_ENV_VAR' StepMetadata string //metadata to be considered, can be filePath or ENV containing JSON in format 'ENV:MY_ENV_VAR'
@ -61,6 +62,7 @@ func addRootFlags(rootCmd *cobra.Command) {
rootCmd.PersistentFlags().StringVar(&GeneralConfig.CustomConfig, "customConfig", ".pipeline/config.yml", "Path to the pipeline configuration file") rootCmd.PersistentFlags().StringVar(&GeneralConfig.CustomConfig, "customConfig", ".pipeline/config.yml", "Path to the pipeline configuration file")
rootCmd.PersistentFlags().StringSliceVar(&GeneralConfig.DefaultConfig, "defaultConfig", []string{".pipeline/defaults.yaml"}, "Default configurations, passed as path to yaml file") rootCmd.PersistentFlags().StringSliceVar(&GeneralConfig.DefaultConfig, "defaultConfig", []string{".pipeline/defaults.yaml"}, "Default configurations, passed as path to yaml file")
rootCmd.PersistentFlags().StringVar(&GeneralConfig.ParametersJSON, "parametersJSON", os.Getenv("PIPER_parametersJSON"), "Parameters to be considered in JSON format") 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", os.Getenv("STAGE_NAME"), "Name of the stage for which configuration should be included") 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") rootCmd.PersistentFlags().StringVar(&GeneralConfig.StepConfigJSON, "stepConfigJSON", os.Getenv("PIPER_stepConfigJSON"), "Step configuration in JSON format")
rootCmd.PersistentFlags().BoolVarP(&GeneralConfig.Verbose, "verbose", "v", false, "verbose output") rootCmd.PersistentFlags().BoolVarP(&GeneralConfig.Verbose, "verbose", "v", false, "verbose output")
@ -71,6 +73,7 @@ func addRootFlags(rootCmd *cobra.Command) {
func PrepareConfig(cmd *cobra.Command, metadata *config.StepData, stepName string, options interface{}, openFile func(s string) (io.ReadCloser, error)) error { func PrepareConfig(cmd *cobra.Command, metadata *config.StepData, stepName string, options interface{}, openFile func(s string) (io.ReadCloser, error)) error {
filters := metadata.GetParameterFilters() filters := metadata.GetParameterFilters()
resourceParams := metadata.GetResourceParameters(GeneralConfig.EnvRootPath, "commonPipelineEnvironment")
flagValues := config.AvailableFlagValues(cmd, &filters) flagValues := config.AvailableFlagValues(cmd, &filters)
@ -108,7 +111,7 @@ func PrepareConfig(cmd *cobra.Command, metadata *config.StepData, stepName strin
defaultConfig = append(defaultConfig, fc) defaultConfig = append(defaultConfig, fc)
} }
stepConfig, err = myConfig.GetStepConfig(flagValues, GeneralConfig.ParametersJSON, customConfig, defaultConfig, filters, metadata.Spec.Inputs.Parameters, GeneralConfig.StageName, stepName) stepConfig, err = myConfig.GetStepConfig(flagValues, GeneralConfig.ParametersJSON, customConfig, defaultConfig, filters, metadata.Spec.Inputs.Parameters, resourceParams, GeneralConfig.StageName, stepName)
if err != nil { if err != nil {
return errors.Wrap(err, "retrieving step configuration failed") return errors.Wrap(err, "retrieving step configuration failed")
} }

View File

@ -3,6 +3,7 @@ package cmd
import ( import (
"github.com/SAP/jenkins-library/pkg/config" "github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -10,11 +11,11 @@ type versionOptions struct {
} }
var myVersionOptions versionOptions var myVersionOptions versionOptions
var versionStepConfigJSON string
// VersionCommand Returns the version of the piper binary // VersionCommand Returns the version of the piper binary
func VersionCommand() *cobra.Command { func VersionCommand() *cobra.Command {
metadata := versionMetadata() metadata := versionMetadata()
var createVersionCmd = &cobra.Command{ var createVersionCmd = &cobra.Command{
Use: "version", Use: "version",
Short: "Returns the version of the piper binary", Short: "Returns the version of the piper binary",
@ -25,6 +26,7 @@ func VersionCommand() *cobra.Command {
return PrepareConfig(cmd, &metadata, "version", &myVersionOptions, config.OpenPiperFile) return PrepareConfig(cmd, &metadata, "version", &myVersionOptions, config.OpenPiperFile)
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return version(myVersionOptions) return version(myVersionOptions)
}, },
} }

View File

@ -5,6 +5,7 @@ import (
"github.com/SAP/jenkins-library/pkg/config" "github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/log"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -25,11 +26,11 @@ type xsDeployOptions struct {
} }
var myXsDeployOptions xsDeployOptions var myXsDeployOptions xsDeployOptions
var xsDeployStepConfigJSON string
// XsDeployCommand Performs xs deployment // XsDeployCommand Performs xs deployment
func XsDeployCommand() *cobra.Command { func XsDeployCommand() *cobra.Command {
metadata := xsDeployMetadata() metadata := xsDeployMetadata()
var createXsDeployCmd = &cobra.Command{ var createXsDeployCmd = &cobra.Command{
Use: "xsDeploy", Use: "xsDeploy",
Short: "Performs xs deployment", Short: "Performs xs deployment",
@ -40,6 +41,7 @@ func XsDeployCommand() *cobra.Command {
return PrepareConfig(cmd, &metadata, "xsDeploy", &myXsDeployOptions, config.OpenPiperFile) return PrepareConfig(cmd, &metadata, "xsDeploy", &myXsDeployOptions, config.OpenPiperFile)
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return xsDeploy(myXsDeployOptions) return xsDeploy(myXsDeployOptions)
}, },
} }
@ -81,6 +83,7 @@ func xsDeployMetadata() config.StepData {
Parameters: []config.StepParameters{ Parameters: []config.StepParameters{
{ {
Name: "deployOpts", Name: "deployOpts",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: false, Mandatory: false,
@ -88,6 +91,7 @@ func xsDeployMetadata() config.StepData {
}, },
{ {
Name: "operationIdLogPattern", Name: "operationIdLogPattern",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: false, Mandatory: false,
@ -95,6 +99,7 @@ func xsDeployMetadata() config.StepData {
}, },
{ {
Name: "mtaPath", Name: "mtaPath",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -102,6 +107,7 @@ func xsDeployMetadata() config.StepData {
}, },
{ {
Name: "action", Name: "action",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: false, Mandatory: false,
@ -109,6 +115,7 @@ func xsDeployMetadata() config.StepData {
}, },
{ {
Name: "mode", Name: "mode",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -116,6 +123,7 @@ func xsDeployMetadata() config.StepData {
}, },
{ {
Name: "operationId", Name: "operationId",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: false, Mandatory: false,
@ -123,6 +131,7 @@ func xsDeployMetadata() config.StepData {
}, },
{ {
Name: "apiUrl", Name: "apiUrl",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -130,6 +139,7 @@ func xsDeployMetadata() config.StepData {
}, },
{ {
Name: "user", Name: "user",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -137,6 +147,7 @@ func xsDeployMetadata() config.StepData {
}, },
{ {
Name: "password", Name: "password",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -144,6 +155,7 @@ func xsDeployMetadata() config.StepData {
}, },
{ {
Name: "org", Name: "org",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -151,6 +163,7 @@ func xsDeployMetadata() config.StepData {
}, },
{ {
Name: "space", Name: "space",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -158,6 +171,7 @@ func xsDeployMetadata() config.StepData {
}, },
{ {
Name: "loginOpts", Name: "loginOpts",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -165,6 +179,7 @@ func xsDeployMetadata() config.StepData {
}, },
{ {
Name: "xsSessionFile", Name: "xsSessionFile",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
Type: "string", Type: "string",
Mandatory: false, Mandatory: false,

View File

@ -82,7 +82,7 @@ func getDeepAliasValue(configMap map[string]interface{}, key string) interface{}
} }
// GetStepConfig provides merged step configuration using defaults, config, if available // GetStepConfig provides merged step configuration using defaults, config, if available
func (c *Config) GetStepConfig(flagValues map[string]interface{}, paramJSON string, configuration io.ReadCloser, defaults []io.ReadCloser, filters StepFilters, parameters []StepParameters, stageName, stepName string) (StepConfig, error) { func (c *Config) GetStepConfig(flagValues map[string]interface{}, paramJSON string, configuration io.ReadCloser, defaults []io.ReadCloser, filters StepFilters, parameters []StepParameters, envParameters map[string]interface{}, stageName, stepName string) (StepConfig, error) {
var stepConfig StepConfig var stepConfig StepConfig
var d PipelineDefaults var d PipelineDefaults
@ -126,6 +126,9 @@ func (c *Config) GetStepConfig(flagValues map[string]interface{}, paramJSON stri
stepConfig.mixIn(def.Steps[stepName], filters.Steps) stepConfig.mixIn(def.Steps[stepName], filters.Steps)
} }
// merge parameters provided by Piper environment
stepConfig.mixIn(envParameters, filters.All)
// read config & merge - general -> steps -> stages // read config & merge - general -> steps -> stages
stepConfig.mixIn(c.General, filters.General) stepConfig.mixIn(c.General, filters.General)
stepConfig.mixIn(c.Steps[stepName], filters.Steps) stepConfig.mixIn(c.Steps[stepName], filters.Steps)

View File

@ -5,9 +5,12 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"os"
"path/filepath"
"strings" "strings"
"testing" "testing"
"github.com/SAP/jenkins-library/pkg/piperenv"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -145,9 +148,26 @@ steps:
}, },
}, },
}, },
{
Name: "pe1",
Scope: []string{"STEPS"},
ResourceRef: []ResourceReference{{Name: "commonPipelineEnvironment", Param: "test_pe1"}},
},
} }
stepConfig, err := c.GetStepConfig(flags, paramJSON, myConfig, defaults, filters, parameterMetadata, "stage1", "step1") stepMeta := StepData{Spec: StepSpec{Inputs: StepInputs{Parameters: parameterMetadata}}}
dir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal("Failed to create temporary directory")
}
// clean up tmp dir
defer os.RemoveAll(dir)
piperenv.SetParameter(filepath.Join(dir, "commonPipelineEnvironment"), "test_pe1", "pe1_val")
stepConfig, err := c.GetStepConfig(flags, paramJSON, myConfig, defaults, filters, parameterMetadata, stepMeta.GetResourceParameters(dir, "commonPipelineEnvironment"), "stage1", "step1")
assert.Equal(t, nil, err, "error occured but none expected") assert.Equal(t, nil, err, "error occured but none expected")
@ -163,7 +183,9 @@ steps:
"p7": "p7_flag", "p7": "p7_flag",
"pd1": "pd1_dependent_default", "pd1": "pd1_dependent_default",
"pd2": "pd2_metadata_default", "pd2": "pd2_metadata_default",
"pe1": "pe1_val",
} }
for k, v := range expected { for k, v := range expected {
t.Run(k, func(t *testing.T) { t.Run(k, func(t *testing.T) {
if stepConfig.Config[k] != v { if stepConfig.Config[k] != v {
@ -191,7 +213,7 @@ steps:
c.openFile = customDefaultsOpenFileMock c.openFile = customDefaultsOpenFileMock
stepConfig, err := c.GetStepConfig(nil, "", ioutil.NopCloser(strings.NewReader(testConfDefaults)), nil, StepFilters{General: []string{"p0"}}, nil, "stage1", "step1") stepConfig, err := c.GetStepConfig(nil, "", ioutil.NopCloser(strings.NewReader(testConfDefaults)), nil, StepFilters{General: []string{"p0"}}, nil, nil, "stage1", "step1")
assert.NoError(t, err, "Error occured but no error expected") assert.NoError(t, err, "Error occured but no error expected")
assert.Equal(t, "p0_custom_default", stepConfig.Config["p0"]) assert.Equal(t, "p0_custom_default", stepConfig.Config["p0"])
@ -204,7 +226,7 @@ steps:
stepParams := []StepParameters{StepParameters{Name: "p0", Scope: []string{"GENERAL"}, Type: "string", Default: "p0_step_default", Aliases: []Alias{{Name: "p0_alias"}}}} stepParams := []StepParameters{StepParameters{Name: "p0", Scope: []string{"GENERAL"}, Type: "string", Default: "p0_step_default", Aliases: []Alias{{Name: "p0_alias"}}}}
testConf := "general:\n p1: p1_conf" testConf := "general:\n p1: p1_conf"
stepConfig, err := c.GetStepConfig(nil, "", ioutil.NopCloser(strings.NewReader(testConf)), nil, StepFilters{General: []string{"p0", "p1"}}, stepParams, "stage1", "step1") stepConfig, err := c.GetStepConfig(nil, "", ioutil.NopCloser(strings.NewReader(testConf)), nil, StepFilters{General: []string{"p0", "p1"}}, stepParams, nil, "stage1", "step1")
assert.NoError(t, err, "Error occured but no error expected") assert.NoError(t, err, "Error occured but no error expected")
assert.Equal(t, "p0_step_default", stepConfig.Config["p0"]) assert.Equal(t, "p0_step_default", stepConfig.Config["p0"])
@ -214,7 +236,7 @@ steps:
t.Run("Failure case config", func(t *testing.T) { t.Run("Failure case config", func(t *testing.T) {
var c Config var c Config
myConfig := ioutil.NopCloser(strings.NewReader("invalid config")) myConfig := ioutil.NopCloser(strings.NewReader("invalid config"))
_, err := c.GetStepConfig(nil, "", myConfig, nil, StepFilters{}, []StepParameters{}, "stage1", "step1") _, err := c.GetStepConfig(nil, "", myConfig, nil, StepFilters{}, []StepParameters{}, nil, "stage1", "step1")
assert.EqualError(t, err, "failed to parse custom pipeline configuration: error unmarshalling \"invalid config\": error unmarshaling JSON: json: cannot unmarshal string into Go value of type config.Config", "default error expected") assert.EqualError(t, err, "failed to parse custom pipeline configuration: error unmarshalling \"invalid config\": error unmarshaling JSON: json: cannot unmarshal string into Go value of type config.Config", "default error expected")
}) })
@ -222,7 +244,7 @@ steps:
var c Config var c Config
myConfig := ioutil.NopCloser(strings.NewReader("")) myConfig := ioutil.NopCloser(strings.NewReader(""))
myDefaults := []io.ReadCloser{ioutil.NopCloser(strings.NewReader("invalid defaults"))} myDefaults := []io.ReadCloser{ioutil.NopCloser(strings.NewReader("invalid defaults"))}
_, err := c.GetStepConfig(nil, "", myConfig, myDefaults, StepFilters{}, []StepParameters{}, "stage1", "step1") _, err := c.GetStepConfig(nil, "", myConfig, myDefaults, StepFilters{}, []StepParameters{}, nil, "stage1", "step1")
assert.EqualError(t, err, "failed to parse pipeline default configuration: error unmarshalling \"invalid defaults\": error unmarshaling JSON: json: cannot unmarshal string into Go value of type config.Config", "default error expected") assert.EqualError(t, err, "failed to parse pipeline default configuration: error unmarshalling \"invalid defaults\": error unmarshaling JSON: json: cannot unmarshal string into Go value of type config.Config", "default error expected")
}) })

7
pkg/config/resources.go Normal file
View File

@ -0,0 +1,7 @@
package config
// InfluxField is the constant for an Influx field
const InfluxField = "field"
// InfluxTag is the constant for an Influx field
const InfluxTag = "tag"

View File

@ -5,6 +5,9 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"path/filepath"
"github.com/SAP/jenkins-library/pkg/piperenv"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -25,8 +28,8 @@ type StepMetadata struct {
// StepSpec defines the spec details for a step, like step inputs, containers, sidecars, ... // StepSpec defines the spec details for a step, like step inputs, containers, sidecars, ...
type StepSpec struct { type StepSpec struct {
Inputs StepInputs `json:"inputs"` Inputs StepInputs `json:"inputs,omitempty"`
// Outputs string `json:"description,omitempty"` Outputs StepOutputs `json:"outputs,omitempty"`
Containers []Container `json:"containers,omitempty"` Containers []Container `json:"containers,omitempty"`
Sidecars []Container `json:"sidecars,omitempty"` Sidecars []Container `json:"sidecars,omitempty"`
} }
@ -43,6 +46,7 @@ type StepParameters struct {
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
LongDescription string `json:"longDescription,omitempty"` LongDescription string `json:"longDescription,omitempty"`
ResourceRef []ResourceReference `json:"resourceRef,omitempty"`
Scope []string `json:"scope"` Scope []string `json:"scope"`
Type string `json:"type"` Type string `json:"type"`
Mandatory bool `json:"mandatory,omitempty"` Mandatory bool `json:"mandatory,omitempty"`
@ -51,6 +55,12 @@ type StepParameters struct {
Conditions []Condition `json:"conditions,omitempty"` Conditions []Condition `json:"conditions,omitempty"`
} }
// ResourceReference defines the parameters of a resource reference
type ResourceReference struct {
Name string `json:"name"`
Param string `json:"param"`
}
// Alias defines a step input parameter alias // Alias defines a step input parameter alias
type Alias struct { type Alias struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
@ -62,6 +72,7 @@ type StepResources struct {
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description,omitempty"` Description string `json:"description,omitempty"`
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
Parameters []map[string]interface{} `json:"params,omitempty"`
Conditions []Condition `json:"conditions,omitempty"` Conditions []Condition `json:"conditions,omitempty"`
} }
@ -72,10 +83,10 @@ type StepSecrets struct {
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
} }
// StepOutputs defines the outputs of a step // StepOutputs defines the outputs of a step step, typically one or multiple resources
//type StepOutputs struct { type StepOutputs struct {
// Name string `json:"name"` Resources []StepResources `json:"resources,omitempty"`
//} }
// Container defines an execution container // Container defines an execution container
type Container struct { type Container struct {
@ -318,6 +329,23 @@ func (m *StepData) GetContextDefaults(stepName string) (io.ReadCloser, error) {
return r, nil return r, nil
} }
// GetResourceParameters retrieves parameters from a named pipeline resource with a defined path
func (m *StepData) GetResourceParameters(path, name string) map[string]interface{} {
resourceParams := map[string]interface{}{}
for _, param := range m.Spec.Inputs.Parameters {
for _, res := range param.ResourceRef {
if res.Name == name {
if val := piperenv.GetParameter(filepath.Join(path, name), res.Param); len(val) > 0 {
resourceParams[param.Name] = val
}
}
}
}
return resourceParams
}
func envVarsAsStringSlice(envVars []EnvVar) []string { func envVarsAsStringSlice(envVars []EnvVar) []string {
e := []string{} e := []string{}
for _, v := range envVars { for _, v := range envVars {

View File

@ -4,6 +4,8 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"os"
"path/filepath"
"strings" "strings"
"testing" "testing"
@ -442,3 +444,62 @@ func TestGetContextDefaults(t *testing.T) {
}) })
}) })
} }
func TestGetResourceParameters(t *testing.T) {
tt := []struct {
in StepData
expected map[string]interface{}
}{
{
in: StepData{Spec: StepSpec{Inputs: StepInputs{}}},
expected: map[string]interface{}{},
},
{
in: StepData{
Spec: StepSpec{Inputs: StepInputs{Parameters: []StepParameters{
{Name: "param1"},
{Name: "param2"},
}}}},
expected: map[string]interface{}{},
},
{
in: StepData{
Spec: StepSpec{Inputs: StepInputs{Parameters: []StepParameters{
{Name: "param1", ResourceRef: []ResourceReference{}},
{Name: "param2", ResourceRef: []ResourceReference{}},
}}}},
expected: map[string]interface{}{},
},
{
in: StepData{
Spec: StepSpec{Inputs: StepInputs{Parameters: []StepParameters{
{Name: "param1", ResourceRef: []ResourceReference{{Name: "notAvailable", Param: "envparam1"}}},
{Name: "param2", ResourceRef: []ResourceReference{{Name: "commonPipelineEnvironment", Param: "envparam2"}}},
}}}},
expected: map[string]interface{}{"param2": "val2"},
},
}
dir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal("Failed to create temporary directory")
}
// clean up tmp dir
defer os.RemoveAll(dir)
cpeDir := filepath.Join(dir, "commonPipelineEnvironment")
err = os.MkdirAll(cpeDir, 0700)
if err != nil {
t.Fatal("Failed to create sub directory")
}
ioutil.WriteFile(filepath.Join(cpeDir, "envparam1"), []byte("val1"), 0700)
ioutil.WriteFile(filepath.Join(cpeDir, "envparam2"), []byte("val2"), 0700)
for run, test := range tt {
t.Run(fmt.Sprintf("Run %v", run), func(t *testing.T) {
got := test.in.GetResourceParameters(dir, "commonPipelineEnvironment")
assert.Equal(t, test.expected, got)
})
}
}

View File

@ -11,6 +11,7 @@ import (
"text/template" "text/template"
"github.com/SAP/jenkins-library/pkg/config" "github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/piperutils"
) )
type stepInfo struct { type stepInfo struct {
@ -21,6 +22,7 @@ type stepInfo struct {
Long string Long string
Metadata []config.StepParameters Metadata []config.StepParameters
OSImport bool OSImport bool
OutputResources []map[string]string
Short string Short string
StepFunc string StepFunc string
StepName string StepName string
@ -31,10 +33,13 @@ const stepGoTemplate = `package cmd
import ( import (
{{ if .OSImport }}"os"{{ end }} {{ if .OSImport }}"os"{{ end }}
{{ if .OutputResources }}"fmt"{{ end }}
{{ if .OutputResources }}"path/filepath"{{ end }}
{{if .ExportPrefix}}{{ .ExportPrefix }} "github.com/SAP/jenkins-library/cmd"{{end}} {{ if .ExportPrefix}}{{ .ExportPrefix }} "github.com/SAP/jenkins-library/cmd"{{ end -}}
"github.com/SAP/jenkins-library/pkg/config" "github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/log"
{{ if .OutputResources }}"github.com/SAP/jenkins-library/pkg/piperenv"{{ end }}
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -43,12 +48,18 @@ type {{ .StepName }}Options struct {
{{ $value.Name | golangName }} {{ $value.Type }} ` + "`json:\"{{$value.Name}},omitempty\"`" + `{{end}} {{ $value.Name | golangName }} {{ $value.Type }} ` + "`json:\"{{$value.Name}},omitempty\"`" + `{{end}}
} }
{{ range $notused, $oRes := .OutputResources }}
{{ index $oRes "def"}}
{{ end }}
var my{{ .StepName | title}}Options {{.StepName}}Options var my{{ .StepName | title}}Options {{.StepName}}Options
var {{ .StepName }}StepConfigJSON string
// {{.CobraCmdFuncName}} {{.Short}} // {{.CobraCmdFuncName}} {{.Short}}
func {{.CobraCmdFuncName}}() *cobra.Command { func {{.CobraCmdFuncName}}() *cobra.Command {
metadata := {{ .StepName }}Metadata() metadata := {{ .StepName }}Metadata()
{{- range $notused, $oRes := .OutputResources }}
var {{ index $oRes "name" }} {{ index $oRes "objectname" }}{{ end }}
var {{.CreateCmdVar}} = &cobra.Command{ var {{.CreateCmdVar}} = &cobra.Command{
Use: "{{.StepName}}", Use: "{{.StepName}}",
Short: "{{.Short}}", Short: "{{.Short}}",
@ -59,7 +70,15 @@ func {{.CobraCmdFuncName}}() *cobra.Command {
return {{if .ExportPrefix}}{{ .ExportPrefix }}.{{end}}PrepareConfig(cmd, &metadata, "{{ .StepName }}", &my{{ .StepName | title}}Options, config.OpenPiperFile) return {{if .ExportPrefix}}{{ .ExportPrefix }}.{{end}}PrepareConfig(cmd, &metadata, "{{ .StepName }}", &my{{ .StepName | title}}Options, config.OpenPiperFile)
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return {{.StepName}}(my{{ .StepName | title }}Options) {{ if .OutputResources -}}
handler := func() {
{{- range $notused, $oRes := .OutputResources }}
{{ index $oRes "name" }}.persist(GeneralConfig.EnvRootPath, "{{ index $oRes "name" }}"){{ end }}
}
log.DeferExitHandler(handler)
defer handler()
{{- end }}
return {{.StepName}}(my{{ .StepName | title }}Options{{ range $notused, $oRes := .OutputResources}}, &{{ index $oRes "name" }}{{ end }})
}, },
} }
@ -84,6 +103,7 @@ func {{ .StepName }}Metadata() config.StepData {
{{- range $key, $value := .Metadata }} {{- range $key, $value := .Metadata }}
{ {
Name: "{{ $value.Name }}", Name: "{{ $value.Name }}",
ResourceRef: []config.ResourceReference{{ "{" }}{{ range $notused, $ref := $value.ResourceRef }}{{ "{" }}Name: "{{ $ref.Name }}", Param: "{{ $ref.Param }}"{{ "}" }},{{ end }}{{ "}" }},
Scope: []string{{ "{" }}{{ range $notused, $scope := $value.Scope }}"{{ $scope }}",{{ end }}{{ "}" }}, Scope: []string{{ "{" }}{{ range $notused, $scope := $value.Scope }}"{{ $scope }}",{{ end }}{{ "}" }},
Type: "{{ $value.Type }}", Type: "{{ $value.Type }}",
Mandatory: {{ $value.Mandatory }}, Mandatory: {{ $value.Mandatory }},
@ -116,6 +136,17 @@ func Test{{.CobraCmdFuncName}}(t *testing.T) {
} }
` `
const stepGoImplementationTemplate = `package cmd
import (
"github.com/SAP/jenkins-library/pkg/log"
)
func {{.StepName}}(config {{ .StepName }}Options{{ range $notused, $oRes := .OutputResources}}, {{ index $oRes "name" }} *{{ index $oRes "objectname" }} {{ end }}) error {
log.Entry().WithField("customKey", "customValue").Info("This is how you write a log message with a custom field ...")
return nil
}
`
// ProcessMetaFiles generates step coding based on step configuration provided in yaml files // ProcessMetaFiles generates step coding based on step configuration provided in yaml files
func ProcessMetaFiles(metadataFiles []string, stepHelperData StepHelperData, docuHelperData DocuHelperData) error { func ProcessMetaFiles(metadataFiles []string, stepHelperData StepHelperData, docuHelperData DocuHelperData) error {
for key := range metadataFiles { for key := range metadataFiles {
@ -141,7 +172,8 @@ func ProcessMetaFiles(metadataFiles []string, stepHelperData StepHelperData, doc
osImport, err = setDefaultParameters(&stepData) osImport, err = setDefaultParameters(&stepData)
checkError(err) checkError(err)
myStepInfo := getStepInfo(&stepData, osImport, stepHelperData.ExportPrefix) myStepInfo, err := getStepInfo(&stepData, osImport, stepHelperData.ExportPrefix)
checkError(err)
step := stepTemplate(myStepInfo) step := stepTemplate(myStepInfo)
err = stepHelperData.WriteFile(fmt.Sprintf("cmd/%v_generated.go", stepData.Metadata.Name), step, 0644) err = stepHelperData.WriteFile(fmt.Sprintf("cmd/%v_generated.go", stepData.Metadata.Name), step, 0644)
@ -150,6 +182,13 @@ func ProcessMetaFiles(metadataFiles []string, stepHelperData StepHelperData, doc
test := stepTestTemplate(myStepInfo) test := stepTestTemplate(myStepInfo)
err = stepHelperData.WriteFile(fmt.Sprintf("cmd/%v_generated_test.go", stepData.Metadata.Name), test, 0644) err = stepHelperData.WriteFile(fmt.Sprintf("cmd/%v_generated_test.go", stepData.Metadata.Name), test, 0644)
checkError(err) checkError(err)
exists, _ := piperutils.FileExists(fmt.Sprintf("cmd/%v.go", stepData.Metadata.Name))
if !exists {
impl := stepImplementation(myStepInfo)
err = stepHelperData.WriteFile(fmt.Sprintf("cmd/%v.go", stepData.Metadata.Name), impl, 0644)
checkError(err)
}
} else { } else {
err = generateStepDocumentation(stepData, docuHelperData) err = generateStepDocumentation(stepData, docuHelperData)
if err != nil { if err != nil {
@ -209,7 +248,9 @@ func setDefaultParameters(stepData *config.StepData) (bool, error) {
return osImportRequired, nil return osImportRequired, nil
} }
func getStepInfo(stepData *config.StepData, osImport bool, exportPrefix string) stepInfo { func getStepInfo(stepData *config.StepData, osImport bool, exportPrefix string) (stepInfo, error) {
oRes, err := getOutputResourceDetails(stepData)
return stepInfo{ return stepInfo{
StepName: stepData.Metadata.Name, StepName: stepData.Metadata.Name,
CobraCmdFuncName: fmt.Sprintf("%vCommand", strings.Title(stepData.Metadata.Name)), CobraCmdFuncName: fmt.Sprintf("%vCommand", strings.Title(stepData.Metadata.Name)),
@ -219,8 +260,79 @@ func getStepInfo(stepData *config.StepData, osImport bool, exportPrefix string)
Metadata: stepData.Spec.Inputs.Parameters, Metadata: stepData.Spec.Inputs.Parameters,
FlagsFunc: fmt.Sprintf("add%vFlags", strings.Title(stepData.Metadata.Name)), FlagsFunc: fmt.Sprintf("add%vFlags", strings.Title(stepData.Metadata.Name)),
OSImport: osImport, OSImport: osImport,
OutputResources: oRes,
ExportPrefix: exportPrefix, ExportPrefix: exportPrefix,
},
err
} }
func getOutputResourceDetails(stepData *config.StepData) ([]map[string]string, error) {
outputResources := []map[string]string{}
for _, res := range stepData.Spec.Outputs.Resources {
currentResource := map[string]string{}
currentResource["name"] = res.Name
switch res.Type {
case "piperEnvironment":
var envResource PiperEnvironmentResource
envResource.Name = res.Name
envResource.StepName = stepData.Metadata.Name
for _, param := range res.Parameters {
paramSections := strings.Split(fmt.Sprintf("%v", param["name"]), "/")
category := ""
name := paramSections[0]
if len(paramSections) > 1 {
name = strings.Join(paramSections[1:], "_")
category = paramSections[0]
if !contains(envResource.Categories, category) {
envResource.Categories = append(envResource.Categories, category)
}
}
envParam := PiperEnvironmentParameter{Category: category, Name: name}
envResource.Parameters = append(envResource.Parameters, envParam)
}
def, err := envResource.StructString()
if err != nil {
return outputResources, err
}
currentResource["def"] = def
currentResource["objectname"] = envResource.StructName()
outputResources = append(outputResources, currentResource)
case "influx":
var influxResource InfluxResource
influxResource.Name = res.Name
influxResource.StepName = stepData.Metadata.Name
for _, measurement := range res.Parameters {
influxMeasurement := InfluxMeasurement{Name: fmt.Sprintf("%v", measurement["name"])}
if fields, ok := measurement["fields"].([]interface{}); ok {
for _, field := range fields {
if fieldParams, ok := field.(map[string]interface{}); ok {
influxMeasurement.Fields = append(influxMeasurement.Fields, InfluxMetric{Name: fmt.Sprintf("%v", fieldParams["name"])})
}
}
}
if tags, ok := measurement["tags"].([]interface{}); ok {
for _, tag := range tags {
if tagParams, ok := tag.(map[string]interface{}); ok {
influxMeasurement.Tags = append(influxMeasurement.Tags, InfluxMetric{Name: fmt.Sprintf("%v", tagParams["name"])})
}
}
}
influxResource.Measurements = append(influxResource.Measurements, influxMeasurement)
}
def, err := influxResource.StructString()
if err != nil {
return outputResources, err
}
currentResource["def"] = def
currentResource["objectname"] = influxResource.StructName()
outputResources = append(outputResources, currentResource)
}
}
return outputResources, nil
} }
// MetadataFiles provides a list of all step metadata files // MetadataFiles provides a list of all step metadata files
@ -244,7 +356,7 @@ func stepTemplate(myStepInfo stepInfo) []byte {
funcMap := template.FuncMap{ funcMap := template.FuncMap{
"flagType": flagType, "flagType": flagType,
"golangName": golangName, "golangName": golangNameTitle,
"title": strings.Title, "title": strings.Title,
"longName": longName, "longName": longName,
} }
@ -263,7 +375,7 @@ func stepTestTemplate(myStepInfo stepInfo) []byte {
funcMap := template.FuncMap{ funcMap := template.FuncMap{
"flagType": flagType, "flagType": flagType,
"golangName": golangName, "golangName": golangNameTitle,
"title": strings.Title, "title": strings.Title,
} }
@ -277,6 +389,22 @@ func stepTestTemplate(myStepInfo stepInfo) []byte {
return generatedCode.Bytes() return generatedCode.Bytes()
} }
func stepImplementation(myStepInfo stepInfo) []byte {
funcMap := template.FuncMap{
"title": strings.Title,
}
tmpl, err := template.New("impl").Funcs(funcMap).Parse(stepGoImplementationTemplate)
checkError(err)
var generatedCode bytes.Buffer
err = tmpl.Execute(&generatedCode, myStepInfo)
checkError(err)
return generatedCode.Bytes()
}
func longName(long string) string { func longName(long string) string {
l := strings.ReplaceAll(long, "`", "` + \"`\" + `") l := strings.ReplaceAll(long, "`", "` + \"`\" + `")
l = strings.TrimSpace(l) l = strings.TrimSpace(l)
@ -290,7 +418,11 @@ func golangName(name string) string {
properName = strings.Replace(properName, "Id", "ID", -1) properName = strings.Replace(properName, "Id", "ID", -1)
properName = strings.Replace(properName, "Json", "JSON", -1) properName = strings.Replace(properName, "Json", "JSON", -1)
properName = strings.Replace(properName, "json", "JSON", -1) properName = strings.Replace(properName, "json", "JSON", -1)
return strings.Title(properName) return properName
}
func golangNameTitle(name string) string {
return strings.Title(golangName(name))
} }
func flagType(paramType string) string { func flagType(paramType string) string {

View File

@ -20,6 +20,22 @@ func configOpenFileMock(name string) (io.ReadCloser, error) {
longDescription: | longDescription: |
Long Test description Long Test description
spec: spec:
outputs:
resources:
- name: commonPipelineEnvironment
type: piperEnvironment
params:
- name: artifactVersion
- name: git/commitId
- name: git/branch
- name: influxTest
type: influx
params:
- name: m1
fields:
- name: f1
tags:
- name: t1
inputs: inputs:
params: params:
- name: param0 - name: param0
@ -75,6 +91,7 @@ func TestProcessMetaFiles(t *testing.T) {
t.Fatalf("failed reading %v", goldenFilePath) t.Fatalf("failed reading %v", goldenFilePath)
} }
assert.Equal(t, expected, files["cmd/testStep_generated.go"]) assert.Equal(t, expected, files["cmd/testStep_generated.go"])
t.Log(string(files["cmd/testStep_generated.go"]))
}) })
t.Run("test code", func(t *testing.T) { t.Run("test code", func(t *testing.T) {
@ -176,7 +193,9 @@ func TestGetStepInfo(t *testing.T) {
}, },
} }
myStepInfo := getStepInfo(&stepData, true, "") myStepInfo, err := getStepInfo(&stepData, true, "")
assert.NoError(t, err)
assert.Equal(t, "testStep", myStepInfo.StepName, "StepName incorrect") assert.Equal(t, "testStep", myStepInfo.StepName, "StepName incorrect")
assert.Equal(t, "TestStepCommand", myStepInfo.CobraCmdFuncName, "CobraCmdFuncName incorrect") assert.Equal(t, "TestStepCommand", myStepInfo.CobraCmdFuncName, "CobraCmdFuncName incorrect")
@ -203,7 +222,7 @@ func TestLongName(t *testing.T) {
} }
} }
func TestGolangName(t *testing.T) { func TestGolangNameTitle(t *testing.T) {
tt := []struct { tt := []struct {
input string input string
expected string expected string
@ -217,7 +236,7 @@ func TestGolangName(t *testing.T) {
} }
for k, v := range tt { for k, v := range tt {
assert.Equal(t, v.expected, golangName(v.input), fmt.Sprintf("wrong golang name for run %v", k)) assert.Equal(t, v.expected, golangNameTitle(v.input), fmt.Sprintf("wrong golang name for run %v", k))
} }
} }

View File

@ -0,0 +1,191 @@
package helper
import (
"bytes"
"fmt"
"strings"
"text/template"
)
// PiperEnvironmentResource defines a piper environement resource which stores data across multiple pipeline steps
type PiperEnvironmentResource struct {
Name string
StepName string
Parameters []PiperEnvironmentParameter
Categories []string
}
// PiperEnvironmentParameter defines a parameter within the Piper environment
type PiperEnvironmentParameter struct {
Category string
Name string
}
const piperEnvStructTemplate = `type {{ .StepName }}{{ .Name | title}} struct {
{{ range $notused, $param := .Parameters }}
{{- if not $param.Category}}{{ $param.Name | golangName }} string{{ end }}
{{- end }}
{{- range $notused, $category := .Categories }}
{{ $category }} struct {
{{- range $notused, $param := $.Parameters }}
{{- if eq $category $param.Category }}
{{ $param.Name | golangName }} string
{{- end }}
{{- end }}
}
{{- end }}
}
func (p *{{ .StepName }}{{ .Name | title}}) persist(path, resourceName string) {
content := []struct{
category string
name string
value string
}{
{{- range $notused, $param := .Parameters }}
{{- if not $param.Category}}
{category: "", name: "{{ $param.Name }}", value: p.{{ $param.Name | golangName}}},
{{- else }}
{category: "{{ $param.Category }}", name: "{{ $param.Name }}", value: p.{{ $param.Category }}.{{ $param.Name | golangName}}},
{{- end }}
{{- end }}
}
errCount := 0
for _, param := range content {
err := piperenv.SetResourceParameter(path, resourceName, filepath.Join(param.category, param.name), param.value)
if err != nil {
log.Entry().WithError(err).Error("Error persisting piper environment.")
errCount++
}
}
if errCount > 0 {
os.Exit(1)
}
}`
// StructName returns the name of the influx resource struct
func (p *PiperEnvironmentResource) StructName() string {
return fmt.Sprintf("%v%v", p.StepName, strings.Title(p.Name))
}
// StructString returns the golang coding for the struct definition of the InfluxResource
func (p *PiperEnvironmentResource) StructString() (string, error) {
funcMap := template.FuncMap{
"title": strings.Title,
"golangName": golangName,
}
tmpl, err := template.New("resources").Funcs(funcMap).Parse(piperEnvStructTemplate)
if err != nil {
return "", err
}
var generatedCode bytes.Buffer
err = tmpl.Execute(&generatedCode, &p)
if err != nil {
return "", err
}
return string(generatedCode.Bytes()), nil
}
// InfluxResource defines an Influx resouece that holds measurement information for a pipeline run
type InfluxResource struct {
Name string
StepName string
Measurements []InfluxMeasurement
}
// InfluxMeasurement defines a measurement for Influx reporting which is defined via a step resource
type InfluxMeasurement struct {
Name string
Fields []InfluxMetric
Tags []InfluxMetric
}
// InfluxMetric defines a metric (column) in an influx measurement
type InfluxMetric struct {
Name string
}
// InfluxMetricContent defines the content of an Inflx metric
type InfluxMetricContent struct {
Measurement string
ValType string
Name string
Value *string
}
const influxStructTemplate = `type {{ .StepName }}{{ .Name | title}} struct {
{{- range $notused, $measurement := .Measurements }}
{{ $measurement.Name }} struct {
fields struct {
{{- range $notused, $field := $measurement.Fields }}
{{ $field.Name | golangName }} string
{{- end }}
}
tags struct {
{{- range $notused, $tag := $measurement.Tags }}
{{ $tag.Name | golangName }} string
{{- end }}
}
}
{{- end }}
}
func (i *{{ .StepName }}{{ .Name | title}}) persist(path, resourceName string) {
measurementContent := []struct{
measurement string
valType string
name string
value string
}{
{{- range $notused, $measurement := .Measurements }}
{{- range $notused, $field := $measurement.Fields }}
{valType: config.InfluxField, measurement: "{{ $measurement.Name }}" , name: "{{ $field.Name }}", value: i.{{ $measurement.Name }}.fields.{{ $field.Name | golangName }}},
{{- end }}
{{- range $notused, $tag := $measurement.Tags }}
{valType: config.InfluxTag, measurement: "{{ $measurement.Name }}" , name: "{{ $tag.Name }}", value: i.{{ $measurement.Name }}.tags.{{ $tag.Name | golangName }}},
{{- end }}
{{- end }}
}
errCount := 0
for _, metric := range measurementContent {
err := piperenv.SetResourceParameter(path, resourceName, filepath.Join(metric.measurement, fmt.Sprintf("%vs", metric.valType), metric.name), metric.value)
if err != nil {
log.Entry().WithError(err).Error("Error persisting influx environment.")
errCount++
}
}
if errCount > 0 {
os.Exit(1)
}
}`
// StructString returns the golang coding for the struct definition of the InfluxResource
func (i *InfluxResource) StructString() (string, error) {
funcMap := template.FuncMap{
"title": strings.Title,
"golangName": golangName,
}
tmpl, err := template.New("resources").Funcs(funcMap).Parse(influxStructTemplate)
if err != nil {
return "", err
}
var generatedCode bytes.Buffer
err = tmpl.Execute(&generatedCode, &i)
if err != nil {
return "", err
}
return string(generatedCode.Bytes()), nil
}
// StructName returns the name of the influx resource struct
func (i *InfluxResource) StructName() string {
return fmt.Sprintf("%v%v", i.StepName, strings.Title(i.Name))
}

View File

@ -0,0 +1,94 @@
package helper
import (
"fmt"
"github.com/stretchr/testify/assert"
"testing"
)
func TestStructString(t *testing.T) {
tt := []struct {
in InfluxResource
expected string
}{
{
in: InfluxResource{
Name: "TestInflux",
StepName: "TestStep",
Measurements: []InfluxMeasurement{
{
Name: "m1",
Fields: []InfluxMetric{{Name: "field1_1"}, {Name: "field1_2"}},
Tags: []InfluxMetric{{Name: "tag1_1"}, {Name: "tag1_2"}},
},
{
Name: "m2",
Fields: []InfluxMetric{{Name: "field2_1"}, {Name: "field2_2"}},
Tags: []InfluxMetric{{Name: "tag2_1"}, {Name: "tag2_2"}},
},
},
},
expected: `type TestStepTestInflux struct {
m1 struct {
fields struct {
field1_1 string
field1_2 string
}
tags struct {
tag1_1 string
tag1_2 string
}
}
m2 struct {
fields struct {
field2_1 string
field2_2 string
}
tags struct {
tag2_1 string
tag2_2 string
}
}
}
func (i *TestStepTestInflux) persist(path, resourceName string) {
measurementContent := []struct{
measurement string
valType string
name string
value string
}{
{valType: config.InfluxField, measurement: "m1" , name: "field1_1", value: i.m1.fields.field1_1},
{valType: config.InfluxField, measurement: "m1" , name: "field1_2", value: i.m1.fields.field1_2},
{valType: config.InfluxTag, measurement: "m1" , name: "tag1_1", value: i.m1.tags.tag1_1},
{valType: config.InfluxTag, measurement: "m1" , name: "tag1_2", value: i.m1.tags.tag1_2},
{valType: config.InfluxField, measurement: "m2" , name: "field2_1", value: i.m2.fields.field2_1},
{valType: config.InfluxField, measurement: "m2" , name: "field2_2", value: i.m2.fields.field2_2},
{valType: config.InfluxTag, measurement: "m2" , name: "tag2_1", value: i.m2.tags.tag2_1},
{valType: config.InfluxTag, measurement: "m2" , name: "tag2_2", value: i.m2.tags.tag2_2},
}
errCount := 0
for _, metric := range measurementContent {
err := piperenv.SetResourceParameter(path, resourceName, filepath.Join(metric.measurement, fmt.Sprintf("%vs", metric.valType), metric.name), metric.value)
if err != nil {
log.Entry().WithError(err).Error("Error persisting influx environment.")
errCount++
}
}
if errCount > 0 {
os.Exit(1)
}
}`,
},
}
for run, test := range tt {
t.Run(fmt.Sprintf("Run %v", run), func(t *testing.T) {
got, err := test.in.StructString()
assert.NoError(t, err)
assert.Equal(t, test.expected, got)
})
}
}

View File

@ -2,10 +2,12 @@ package cmd
import ( import (
"os" "os"
"fmt"
"path/filepath"
"github.com/SAP/jenkins-library/pkg/config" "github.com/SAP/jenkins-library/pkg/config"
"github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/log"
"github.com/SAP/jenkins-library/pkg/piperenv"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -15,12 +17,83 @@ type testStepOptions struct {
Param2 string `json:"param2,omitempty"` Param2 string `json:"param2,omitempty"`
} }
type testStepCommonPipelineEnvironment struct {
artifactVersion string
git struct {
commitID string
branch string
}
}
func (p *testStepCommonPipelineEnvironment) persist(path, resourceName string) {
content := []struct{
category string
name string
value string
}{
{category: "", name: "artifactVersion", value: p.artifactVersion},
{category: "git", name: "commitId", value: p.git.commitID},
{category: "git", name: "branch", value: p.git.branch},
}
errCount := 0
for _, param := range content {
err := piperenv.SetResourceParameter(path, resourceName, filepath.Join(param.category, param.name), param.value)
if err != nil {
log.Entry().WithError(err).Error("Error persisting piper environment.")
errCount++
}
}
if errCount > 0 {
os.Exit(1)
}
}
type testStepInfluxTest struct {
m1 struct {
fields struct {
f1 string
}
tags struct {
t1 string
}
}
}
func (i *testStepInfluxTest) persist(path, resourceName string) {
measurementContent := []struct{
measurement string
valType string
name string
value string
}{
{valType: config.InfluxField, measurement: "m1" , name: "f1", value: i.m1.fields.f1},
{valType: config.InfluxTag, measurement: "m1" , name: "t1", value: i.m1.tags.t1},
}
errCount := 0
for _, metric := range measurementContent {
err := piperenv.SetResourceParameter(path, resourceName, filepath.Join(metric.measurement, fmt.Sprintf("%vs", metric.valType), metric.name), metric.value)
if err != nil {
log.Entry().WithError(err).Error("Error persisting influx environment.")
errCount++
}
}
if errCount > 0 {
os.Exit(1)
}
}
var myTestStepOptions testStepOptions var myTestStepOptions testStepOptions
var testStepStepConfigJSON string
// TestStepCommand Test description // TestStepCommand Test description
func TestStepCommand() *cobra.Command { func TestStepCommand() *cobra.Command {
metadata := testStepMetadata() metadata := testStepMetadata()
var commonPipelineEnvironment testStepCommonPipelineEnvironment
var influxTest testStepInfluxTest
var createTestStepCmd = &cobra.Command{ var createTestStepCmd = &cobra.Command{
Use: "testStep", Use: "testStep",
Short: "Test description", Short: "Test description",
@ -31,7 +104,13 @@ func TestStepCommand() *cobra.Command {
return PrepareConfig(cmd, &metadata, "testStep", &myTestStepOptions, config.OpenPiperFile) return PrepareConfig(cmd, &metadata, "testStep", &myTestStepOptions, config.OpenPiperFile)
}, },
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
return testStep(myTestStepOptions) handler := func() {
commonPipelineEnvironment.persist(GeneralConfig.EnvRootPath, "commonPipelineEnvironment")
influxTest.persist(GeneralConfig.EnvRootPath, "influxTest")
}
log.DeferExitHandler(handler)
defer handler()
return testStep(myTestStepOptions, &commonPipelineEnvironment, &influxTest)
}, },
} }
@ -56,6 +135,7 @@ func testStepMetadata() config.StepData {
Parameters: []config.StepParameters{ Parameters: []config.StepParameters{
{ {
Name: "param0", Name: "param0",
ResourceRef: []config.ResourceReference{},
Scope: []string{"GENERAL","PARAMETERS",}, Scope: []string{"GENERAL","PARAMETERS",},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,
@ -63,6 +143,7 @@ func testStepMetadata() config.StepData {
}, },
{ {
Name: "param1", Name: "param1",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS",}, Scope: []string{"PARAMETERS",},
Type: "string", Type: "string",
Mandatory: false, Mandatory: false,
@ -70,6 +151,7 @@ func testStepMetadata() config.StepData {
}, },
{ {
Name: "param2", Name: "param2",
ResourceRef: []config.ResourceReference{},
Scope: []string{"PARAMETERS",}, Scope: []string{"PARAMETERS",},
Type: "string", Type: "string",
Mandatory: true, Mandatory: true,

View File

@ -28,3 +28,8 @@ func SetVerbose(verbose bool) {
func SetStepName(stepName string) { func SetStepName(stepName string) {
logger = Entry().WithField("stepName", stepName) logger = Entry().WithField("stepName", stepName)
} }
// DeferExitHandler registers a logrus exit handler to allow cleanup activities.
func DeferExitHandler(handler func()) {
logrus.DeferExitHandler(handler)
}

View File

@ -0,0 +1,62 @@
package piperenv
import (
"io/ioutil"
"os"
"path/filepath"
"github.com/SAP/jenkins-library/pkg/log"
)
// This file contains functions used to read/write pipeline environment data from/to disk.
// The content of a written file is the value. For the custom parameters this could for example also be a JSON representation of a more complex value.
// SetResourceParameter sets a resource parameter in the environment stored in the file system
func SetResourceParameter(path, resourceName, paramName, value string) error {
paramPath := filepath.Join(path, resourceName, paramName)
return writeToDisk(paramPath, []byte(value))
}
// GetResourceParameter reads a resource parameter from the environment stored in the file system
func GetResourceParameter(path, resourceName, paramName string) string {
paramPath := filepath.Join(path, resourceName, paramName)
return readFromDisk(paramPath)
}
// SetParameter sets any parameter in the pipeline environment or another environment stored in the file system
func SetParameter(path, name, value string) error {
paramPath := filepath.Join(path, name)
return writeToDisk(paramPath, []byte(value))
}
// GetParameter reads any parameter from the pipeline environment or another environment stored in the file system
func GetParameter(path, name string) string {
paramPath := filepath.Join(path, name)
return readFromDisk(paramPath)
}
func writeToDisk(filename string, data []byte) error {
if _, err := os.Stat(filepath.Dir(filename)); os.IsNotExist(err) {
log.Entry().Debugf("Creating directory: %v", filepath.Dir(filename))
os.MkdirAll(filepath.Dir(filename), 0700)
}
//ToDo: make sure to not overwrite file but rather add another file? Create error if already existing?
if len(data) > 0 {
log.Entry().Debugf("Writing file to disk: %v", filename)
return ioutil.WriteFile(filename, data, 0700)
}
return nil
}
func readFromDisk(filename string) string {
//ToDo: if multiple files exist, read from latest file
log.Entry().Debugf("Reading file from disk: %v", filename)
v, err := ioutil.ReadFile(filename)
val := string(v)
if err != nil {
val = ""
}
return val
}

View File

@ -0,0 +1,51 @@
package piperenv
import (
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/assert"
)
func TestSetResourceParameter(t *testing.T) {
dir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal("Failed to create temporary directory")
}
// clean up tmp dir
defer os.RemoveAll(dir)
err = SetResourceParameter(dir, "testRes", "testParam", "testVal")
assert.NoError(t, err, "Error occured but none expected")
assert.Equal(t, "testVal", GetResourceParameter(dir, "testRes", "testParam"))
}
func TestSetParameter(t *testing.T) {
dir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal("Failed to create temporary directory")
}
// clean up tmp dir
defer os.RemoveAll(dir)
err = SetParameter(dir, "testParam", "testVal")
assert.NoError(t, err, "Error occured but none expected")
assert.Equal(t, "testVal", GetParameter(dir, "testParam"))
}
func TestReadFromDisk(t *testing.T) {
dir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal("Failed to create temporary directory")
}
// clean up tmp dir
defer os.RemoveAll(dir)
assert.Equal(t, "", GetParameter(dir, "testParamNotExistingYet"))
}

View File

@ -18,6 +18,10 @@ spec:
- name: githubTokenCredentialsId - name: githubTokenCredentialsId
description: Jenkins 'Secret text' credentials ID containing token to authenticate to GitHub. description: Jenkins 'Secret text' credentials ID containing token to authenticate to GitHub.
type: jenkins type: jenkins
resources:
- name: commonPipelineEnvironment
resourceSpec:
type: piperEnvironment
params: params:
- name: addClosedIssues - name: addClosedIssues
description: 'If set to `true`, closed issues and merged pull-requests since the last release will added below the `releaseBodyHeader`' description: 'If set to `true`, closed issues and merged pull-requests since the last release will added below the `releaseBodyHeader`'
@ -35,6 +39,18 @@ spec:
- STEPS - STEPS
type: bool type: bool
default: false default: false
- name: apiUrl
aliases:
- name: githubApiUrl
description: Set the GitHub API url.
scope:
- GENERAL
- PARAMETERS
- STAGES
- STEPS
type: string
default: https://api.github.com
mandatory: true
- name: assetPath - name: assetPath
description: Path to a release asset which should be uploaded to the list of release assets. description: Path to a release asset which should be uploaded to the list of release assets.
scope: scope:
@ -57,32 +73,40 @@ spec:
- STAGES - STAGES
- STEPS - STEPS
type: '[]string' type: '[]string'
- name: apiUrl - name: labels
aliases: description: 'Labels to include in issue search.'
- name: githubApiUrl
description: Set the GitHub API url.
scope: scope:
- GENERAL
- PARAMETERS - PARAMETERS
- STAGES - STAGES
- STEPS - STEPS
type: string type: '[]string'
default: https://api.github.com
mandatory: true
- name: owner - name: owner
aliases: aliases:
- name: githubOrg - name: githubOrg
description: 'Set the GitHub organization.' description: 'Set the GitHub organization.'
resourceRef:
- name: commonPipelineEnvironment
param: github/owner
scope: scope:
- PARAMETERS - PARAMETERS
- STAGES - STAGES
- STEPS - STEPS
type: string type: string
mandatory: true mandatory: true
- name: releaseBodyHeader
description: Content which will appear for the release.
scope:
- PARAMETERS
- STAGES
- STEPS
type: string
- name: repository - name: repository
aliases: aliases:
- name: githubRepo - name: githubRepo
description: 'Set the GitHub repository.' description: 'Set the GitHub repository.'
resourceRef:
- name: commonPipelineEnvironment
param: github/repository
scope: scope:
- PARAMETERS - PARAMETERS
- STAGES - STAGES
@ -124,22 +148,11 @@ spec:
type: string type: string
default: https://uploads.github.com default: https://uploads.github.com
mandatory: true mandatory: true
- name: labels
description: 'Labels to include in issue search.'
scope:
- PARAMETERS
- STAGES
- STEPS
type: '[]string'
- name: releaseBodyHeader
description: Content which will appear for the release.
scope:
- PARAMETERS
- STAGES
- STEPS
type: string
- name: version - name: version
description: 'Define the version number which will be written as tag as well as release name.' description: 'Define the version number which will be written as tag as well as release name.'
resourceRef:
- name: commonPipelineEnvironment
param: artifactVersion
scope: scope:
- PARAMETERS - PARAMETERS
- STAGES - STAGES

View File

@ -2,20 +2,27 @@ import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.rules.RuleChain import org.junit.rules.RuleChain
import util.BasePiperTest import util.BasePiperTest
import util.JenkinsFileExistsRule
import util.JenkinsWriteFileRule
import util.JenkinsReadYamlRule import util.JenkinsReadYamlRule
import util.Rules import util.Rules
import static org.hamcrest.CoreMatchers.is import static org.hamcrest.CoreMatchers.is
import static org.hamcrest.Matchers.contains
import static org.hamcrest.Matchers.hasItem import static org.hamcrest.Matchers.hasItem
import static org.junit.Assert.assertThat import static org.junit.Assert.assertThat
class CommonPipelineEnvironmentTest extends BasePiperTest { class CommonPipelineEnvironmentTest extends BasePiperTest {
private JenkinsWriteFileRule writeFileRule = new JenkinsWriteFileRule(this)
private JenkinsFileExistsRule fileExistsRule = new JenkinsFileExistsRule(this, [])
@Rule @Rule
public RuleChain rules = Rules public RuleChain rules = Rules
.getCommonRules(this) .getCommonRules(this)
.around(new JenkinsReadYamlRule(this) .around(new JenkinsReadYamlRule(this))
) .around(writeFileRule)
.around(fileExistsRule)
@Test @Test
void testCustomValueList() { void testCustomValueList() {
@ -34,4 +41,14 @@ class CommonPipelineEnvironmentTest extends BasePiperTest {
assertThat(nullScript.commonPipelineEnvironment.getValue('myList').key1, is('val1')) assertThat(nullScript.commonPipelineEnvironment.getValue('myList').key1, is('val1'))
assertThat(nullScript.commonPipelineEnvironment.getValue('myList').key2, is('val2')) assertThat(nullScript.commonPipelineEnvironment.getValue('myList').key2, is('val2'))
} }
@Test
void testWritetoDisk() {
nullScript.commonPipelineEnvironment.artifactVersion = '1.0.0'
nullScript.commonPipelineEnvironment.setValue('custom1', 'customVal1')
nullScript.commonPipelineEnvironment.writeToDisk(nullScript)
assertThat(writeFileRule.files['.pipeline/commonPipelineEnvironment/artifactVersion'], is('1.0.0'))
assertThat(writeFileRule.files['.pipeline/commonPipelineEnvironment/custom/custom1'], is('customVal1'))
}
} }

View File

@ -5,6 +5,7 @@ import org.junit.rules.ExpectedException
import org.junit.rules.RuleChain import org.junit.rules.RuleChain
import util.BasePiperTest import util.BasePiperTest
import util.JenkinsCredentialsRule import util.JenkinsCredentialsRule
import util.JenkinsFileExistsRule
import util.JenkinsLoggingRule import util.JenkinsLoggingRule
import util.JenkinsReadJsonRule import util.JenkinsReadJsonRule
import util.JenkinsReadYamlRule import util.JenkinsReadYamlRule
@ -23,6 +24,7 @@ class GithubPublishReleaseTest extends BasePiperTest {
private JenkinsShellCallRule shellCallRule = new JenkinsShellCallRule(this) private JenkinsShellCallRule shellCallRule = new JenkinsShellCallRule(this)
private JenkinsStepRule stepRule = new JenkinsStepRule(this) private JenkinsStepRule stepRule = new JenkinsStepRule(this)
private JenkinsWriteFileRule writeFileRule = new JenkinsWriteFileRule(this) private JenkinsWriteFileRule writeFileRule = new JenkinsWriteFileRule(this)
private JenkinsFileExistsRule fileExistsRule = new JenkinsFileExistsRule(this, [])
private List withEnvArgs = [] private List withEnvArgs = []
@ -35,6 +37,7 @@ class GithubPublishReleaseTest extends BasePiperTest {
.around(shellCallRule) .around(shellCallRule)
.around(stepRule) .around(stepRule)
.around(writeFileRule) .around(writeFileRule)
.around(fileExistsRule)
@Before @Before
void init() { void init() {
@ -58,26 +61,6 @@ class GithubPublishReleaseTest extends BasePiperTest {
// asserts // asserts
assertThat(writeFileRule.files['metadata/githubrelease.yaml'], containsString('name: githubPublishRelease')) assertThat(writeFileRule.files['metadata/githubrelease.yaml'], containsString('name: githubPublishRelease'))
assertThat(withEnvArgs[0], allOf(startsWith('PIPER_parametersJSON'), containsString('"testParam":"This is test content"'))) assertThat(withEnvArgs[0], allOf(startsWith('PIPER_parametersJSON'), containsString('"testParam":"This is test content"')))
assertThat(withEnvArgs[1], is('PIPER_owner='))
assertThat(withEnvArgs[2], is('PIPER_repository='))
assertThat(withEnvArgs[3], is('PIPER_version='))
assertThat(shellCallRule.shell[1], is('./piper githubPublishRelease --token thisIsATestToken')) assertThat(shellCallRule.shell[1], is('./piper githubPublishRelease --token thisIsATestToken'))
} }
@Test
void testGithubPublishReleaseWithEnv() {
nullScript.commonPipelineEnvironment.setArtifactVersion('1.0.0')
nullScript.commonPipelineEnvironment.setGithubOrg('TestOrg')
nullScript.commonPipelineEnvironment.setGithubRepo('TestRepo')
stepRule.step.githubPublishRelease(
juStabUtils: utils,
script: nullScript
)
// asserts
assertThat(withEnvArgs[1], is('PIPER_owner=TestOrg'))
assertThat(withEnvArgs[2], is('PIPER_repository=TestRepo'))
assertThat(withEnvArgs[3], is('PIPER_version=1.0.0'))
}
} }

View File

@ -40,13 +40,13 @@ class JenkinsFileExistsRule implements TestRule {
void evaluate() throws Throwable { void evaluate() throws Throwable {
testInstance.helper.registerAllowedMethod('fileExists', [String.class], {s -> testInstance.helper.registerAllowedMethod('fileExists', [String.class], {s ->
queriedFiles.add(s) queriedFiles.add(s.toString())
return s in existingFiles return s.toString() in existingFiles
}) })
testInstance.helper.registerAllowedMethod('fileExists', [Map.class], {m -> testInstance.helper.registerAllowedMethod('fileExists', [Map.class], {m ->
queriedFiles.add(m.file) queriedFiles.add(m.file.toString())
return m.file in existingFiles} return m.file.toString() in existingFiles}
) )
base.evaluate() base.evaluate()

View File

@ -144,8 +144,74 @@ class commonPipelineEnvironment implements Serializable {
config = ConfigurationMerger.merge(configuration.get('stages')?.get(stageName) ?: [:], null, config) config = ConfigurationMerger.merge(configuration.get('stages')?.get(stageName) ?: [:], null, config)
return config return config
} }
void writeToDisk(script) {
def files = [
[filename: '.pipeline/commonPipelineEnvironment/artifactVersion', content: artifactVersion],
[filename: '.pipeline/commonPipelineEnvironment/github/owner', content: githubOrg],
[filename: '.pipeline/commonPipelineEnvironment/github/repository', content: githubRepo],
[filename: '.pipeline/commonPipelineEnvironment/git/branch', content: gitBranch],
[filename: '.pipeline/commonPipelineEnvironment/git/commitId', content: gitCommitId],
[filename: '.pipeline/commonPipelineEnvironment/git/commitMessage', content: gitCommitMessage],
]
files.each({f ->
if (f.content && !script.fileExists(f.filename)) {
script.writeFile file: f.filename, text: f.content
}
})
valueMap.each({key, value ->
def fileName = ".pipeline/commonPipelineEnvironment/custom/${key}"
if (value && !script.fileExists(fileName)) {
//ToDo: check for value type and act accordingly?
script.writeFile file: fileName, text: value
}
})
}
void readFromDisk() {
def file = '.pipeline/commonPipelineEnvironment/artifactVersion'
if (fileExists(file)) {
artifactVersion = readFile(file)
}
file = '.pipeline/commonPipelineEnvironment/github/owner'
if (fileExists(file)) {
githubOrg = readFile(file)
}
file = '.pipeline/commonPipelineEnvironment/github/repository'
if (fileExists(file)) {
githubRepo = readFile(file)
}
file = '.pipeline/commonPipelineEnvironment/git/branch'
if (fileExists(file)) {
gitBranch = readFile(file)
}
file = '.pipeline/commonPipelineEnvironment/git/commitId'
if (fileExists(file)) {
gitCommitId = readFile(file)
}
file = '.pipeline/commonPipelineEnvironment/git/commitMessage'
if (fileExists(file)) {
gitCommitMessage = readFile(file)
}
def customValues = findFiles(glob: '.pipeline/commonPipelineEnvironment/custom/*')
customValues.each({f ->
def fileName = f.getName()
def param = fileName.split('/')[fileName.split('\\/').size()-1]
valueMap[param] = readFile(f.getPath())
})
}
List getCustomDefaults() { List getCustomDefaults() {
DefaultValueCache.getInstance().getCustomDefaults() DefaultValueCache.getInstance().getCustomDefaults()
} }
} }

View File

@ -23,14 +23,12 @@ void call(Map parameters = [:]) {
new PiperGoUtils(this, utils).unstashPiperBin() new PiperGoUtils(this, utils).unstashPiperBin()
utils.unstash('pipelineConfigAndTests') utils.unstash('pipelineConfigAndTests')
script.commonPipelineEnvironment.writeToDisk(script)
writeFile(file: METADATA_FILE, text: libraryResource(METADATA_FILE)) writeFile(file: METADATA_FILE, text: libraryResource(METADATA_FILE))
withEnv([ withEnv([
"PIPER_parametersJSON=${groovy.json.JsonOutput.toJson(parameters)}", "PIPER_parametersJSON=${groovy.json.JsonOutput.toJson(parameters)}",
"PIPER_owner=${script.commonPipelineEnvironment.getGithubOrg()?:''}",
"PIPER_repository=${script.commonPipelineEnvironment.getGithubRepo()?:''}",
"PIPER_version=${script.commonPipelineEnvironment.getArtifactVersion()?:''}"
]) { ]) {
// get context configuration // get context configuration
config = readJSON (text: sh(returnStdout: true, script: "./piper getConfig --contextConfig --stepMetadata '${METADATA_FILE}'")) config = readJSON (text: sh(returnStdout: true, script: "./piper getConfig --contextConfig --stepMetadata '${METADATA_FILE}'"))