You've already forked sap-jenkins-library
mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-07-15 01:34:38 +02:00
Merge branch 'master' into eclipsecomplains
This commit is contained in:
5
.gitignore
vendored
5
.gitignore
vendored
@ -8,6 +8,7 @@ reports
|
|||||||
.classpath
|
.classpath
|
||||||
.project
|
.project
|
||||||
*~
|
*~
|
||||||
|
.vscode
|
||||||
|
|
||||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
hs_err_pid*
|
hs_err_pid*
|
||||||
@ -19,5 +20,5 @@ documentation/docs-gen
|
|||||||
consumer-test/**/workspace
|
consumer-test/**/workspace
|
||||||
|
|
||||||
*.code-workspace
|
*.code-workspace
|
||||||
piper
|
/piper
|
||||||
piper.exe
|
/piper.exe
|
||||||
|
@ -86,8 +86,6 @@ func generateConfig() error {
|
|||||||
return errors.Wrap(err, "getting step config failed")
|
return errors.Wrap(err, "getting step config failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
//ToDo: Check for mandatory parameters
|
|
||||||
|
|
||||||
myConfigJSON, _ := config.GetJSON(stepConfig.Config)
|
myConfigJSON, _ := config.GetJSON(stepConfig.Config)
|
||||||
|
|
||||||
fmt.Println(myConfigJSON)
|
fmt.Println(myConfigJSON)
|
||||||
|
217
cmd/githubPublishRelease.go
Normal file
217
cmd/githubPublishRelease.go
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"mime"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/SAP/jenkins-library/pkg/log"
|
||||||
|
"github.com/google/go-github/v28/github"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
|
piperGithub "github.com/SAP/jenkins-library/pkg/github"
|
||||||
|
)
|
||||||
|
|
||||||
|
type githubRepoClient interface {
|
||||||
|
CreateRelease(ctx context.Context, owner string, repo string, release *github.RepositoryRelease) (*github.RepositoryRelease, *github.Response, error)
|
||||||
|
DeleteReleaseAsset(ctx context.Context, owner string, repo string, id int64) (*github.Response, error)
|
||||||
|
GetLatestRelease(ctx context.Context, owner string, repo string) (*github.RepositoryRelease, *github.Response, error)
|
||||||
|
ListReleaseAssets(ctx context.Context, owner string, repo string, id int64, opt *github.ListOptions) ([]*github.ReleaseAsset, *github.Response, error)
|
||||||
|
UploadReleaseAsset(ctx context.Context, owner string, repo string, id int64, opt *github.UploadOptions, file *os.File) (*github.ReleaseAsset, *github.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type githubIssueClient interface {
|
||||||
|
ListByRepo(ctx context.Context, owner string, repo string, opt *github.IssueListByRepoOptions) ([]*github.Issue, *github.Response, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func githubPublishRelease(myGithubPublishReleaseOptions githubPublishReleaseOptions) error {
|
||||||
|
ctx, client, err := piperGithub.NewClient(myGithubPublishReleaseOptions.Token, myGithubPublishReleaseOptions.APIURL, myGithubPublishReleaseOptions.UploadURL)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).Fatal("Failed to get GitHub client.")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = runGithubPublishRelease(ctx, &myGithubPublishReleaseOptions, client.Repositories, client.Issues)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).Fatal("Failed to publish GitHub release.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func runGithubPublishRelease(ctx context.Context, myGithubPublishReleaseOptions *githubPublishReleaseOptions, ghRepoClient githubRepoClient, ghIssueClient githubIssueClient) error {
|
||||||
|
|
||||||
|
var publishedAt github.Timestamp
|
||||||
|
|
||||||
|
lastRelease, resp, err := ghRepoClient.GetLatestRelease(ctx, myGithubPublishReleaseOptions.Owner, myGithubPublishReleaseOptions.Repository)
|
||||||
|
if err != nil {
|
||||||
|
if resp.StatusCode == 404 {
|
||||||
|
//no previous release found -> first release
|
||||||
|
myGithubPublishReleaseOptions.AddDeltaToLastRelease = false
|
||||||
|
log.Entry().Debug("This is the first release.")
|
||||||
|
} else {
|
||||||
|
return errors.Wrap(err, "Error occured when retrieving latest GitHub release.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
publishedAt = lastRelease.GetPublishedAt()
|
||||||
|
log.Entry().Debugf("Previous GitHub release published: '%v'", publishedAt)
|
||||||
|
|
||||||
|
//updating assets only supported on latest release
|
||||||
|
if myGithubPublishReleaseOptions.UpdateAsset && myGithubPublishReleaseOptions.Version == "latest" {
|
||||||
|
return uploadReleaseAsset(ctx, lastRelease.GetID(), myGithubPublishReleaseOptions, ghRepoClient)
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseBody := ""
|
||||||
|
|
||||||
|
if len(myGithubPublishReleaseOptions.ReleaseBodyHeader) > 0 {
|
||||||
|
releaseBody += myGithubPublishReleaseOptions.ReleaseBodyHeader + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
if myGithubPublishReleaseOptions.AddClosedIssues {
|
||||||
|
releaseBody += getClosedIssuesText(ctx, publishedAt, myGithubPublishReleaseOptions, ghIssueClient)
|
||||||
|
}
|
||||||
|
|
||||||
|
if myGithubPublishReleaseOptions.AddDeltaToLastRelease {
|
||||||
|
releaseBody += getReleaseDeltaText(myGithubPublishReleaseOptions, lastRelease)
|
||||||
|
}
|
||||||
|
|
||||||
|
release := github.RepositoryRelease{
|
||||||
|
TagName: &myGithubPublishReleaseOptions.Version,
|
||||||
|
TargetCommitish: &myGithubPublishReleaseOptions.Commitish,
|
||||||
|
Name: &myGithubPublishReleaseOptions.Version,
|
||||||
|
Body: &releaseBody,
|
||||||
|
}
|
||||||
|
|
||||||
|
createdRelease, _, err := ghRepoClient.CreateRelease(ctx, myGithubPublishReleaseOptions.Owner, myGithubPublishReleaseOptions.Repository, &release)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Creation of release '%v' failed", *release.TagName)
|
||||||
|
}
|
||||||
|
log.Entry().Infof("Release %v created on %v/%v", *createdRelease.TagName, myGithubPublishReleaseOptions.Owner, myGithubPublishReleaseOptions.Repository)
|
||||||
|
|
||||||
|
if len(myGithubPublishReleaseOptions.AssetPath) > 0 {
|
||||||
|
return uploadReleaseAsset(ctx, createdRelease.GetID(), myGithubPublishReleaseOptions, ghRepoClient)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getClosedIssuesText(ctx context.Context, publishedAt github.Timestamp, myGithubPublishReleaseOptions *githubPublishReleaseOptions, ghIssueClient githubIssueClient) string {
|
||||||
|
closedIssuesText := ""
|
||||||
|
|
||||||
|
options := github.IssueListByRepoOptions{
|
||||||
|
State: "closed",
|
||||||
|
Direction: "asc",
|
||||||
|
Since: publishedAt.Time,
|
||||||
|
}
|
||||||
|
if len(myGithubPublishReleaseOptions.Labels) > 0 {
|
||||||
|
options.Labels = myGithubPublishReleaseOptions.Labels
|
||||||
|
}
|
||||||
|
ghIssues, _, err := ghIssueClient.ListByRepo(ctx, myGithubPublishReleaseOptions.Owner, myGithubPublishReleaseOptions.Repository, &options)
|
||||||
|
if err != nil {
|
||||||
|
log.Entry().WithError(err).Error("Failed to get GitHub issues.")
|
||||||
|
}
|
||||||
|
|
||||||
|
prTexts := []string{"**List of closed pull-requests since last release**"}
|
||||||
|
issueTexts := []string{"**List of closed issues since last release**"}
|
||||||
|
|
||||||
|
for _, issue := range ghIssues {
|
||||||
|
if issue.IsPullRequest() && !isExcluded(issue, myGithubPublishReleaseOptions.ExcludeLabels) {
|
||||||
|
prTexts = append(prTexts, fmt.Sprintf("[#%v](%v): %v", issue.GetNumber(), issue.GetHTMLURL(), issue.GetTitle()))
|
||||||
|
log.Entry().Debugf("Added PR #%v to release", issue.GetNumber())
|
||||||
|
} else if !issue.IsPullRequest() && !isExcluded(issue, myGithubPublishReleaseOptions.ExcludeLabels) {
|
||||||
|
issueTexts = append(issueTexts, fmt.Sprintf("[#%v](%v): %v", issue.GetNumber(), issue.GetHTMLURL(), issue.GetTitle()))
|
||||||
|
log.Entry().Debugf("Added Issue #%v to release", issue.GetNumber())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(prTexts) > 1 {
|
||||||
|
closedIssuesText += "\n" + strings.Join(prTexts, "\n") + "\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(issueTexts) > 1 {
|
||||||
|
closedIssuesText += "\n" + strings.Join(issueTexts, "\n") + "\n"
|
||||||
|
}
|
||||||
|
return closedIssuesText
|
||||||
|
}
|
||||||
|
|
||||||
|
func getReleaseDeltaText(myGithubPublishReleaseOptions *githubPublishReleaseOptions, lastRelease *github.RepositoryRelease) string {
|
||||||
|
releaseDeltaText := ""
|
||||||
|
|
||||||
|
//add delta link to previous release
|
||||||
|
releaseDeltaText += "\n**Changes**\n"
|
||||||
|
releaseDeltaText += fmt.Sprintf(
|
||||||
|
"[%v...%v](%v/%v/%v/compare/%v...%v)\n",
|
||||||
|
lastRelease.GetTagName(),
|
||||||
|
myGithubPublishReleaseOptions.Version,
|
||||||
|
myGithubPublishReleaseOptions.ServerURL,
|
||||||
|
myGithubPublishReleaseOptions.Owner,
|
||||||
|
myGithubPublishReleaseOptions.Repository,
|
||||||
|
lastRelease.GetTagName(), myGithubPublishReleaseOptions.Version,
|
||||||
|
)
|
||||||
|
|
||||||
|
return releaseDeltaText
|
||||||
|
}
|
||||||
|
|
||||||
|
func uploadReleaseAsset(ctx context.Context, releaseID int64, myGithubPublishReleaseOptions *githubPublishReleaseOptions, ghRepoClient githubRepoClient) error {
|
||||||
|
|
||||||
|
assets, _, err := ghRepoClient.ListReleaseAssets(ctx, myGithubPublishReleaseOptions.Owner, myGithubPublishReleaseOptions.Repository, releaseID, &github.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Failed to get list of release assets.")
|
||||||
|
}
|
||||||
|
var assetID int64
|
||||||
|
for _, a := range assets {
|
||||||
|
if a.GetName() == filepath.Base(myGithubPublishReleaseOptions.AssetPath) {
|
||||||
|
assetID = a.GetID()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if assetID != 0 {
|
||||||
|
//asset needs to be deleted first since API does not allow for replacement
|
||||||
|
_, err := ghRepoClient.DeleteReleaseAsset(ctx, myGithubPublishReleaseOptions.Owner, myGithubPublishReleaseOptions.Repository, assetID)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Failed to delete release asset.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaType := mime.TypeByExtension(filepath.Ext(myGithubPublishReleaseOptions.AssetPath))
|
||||||
|
if mediaType == "" {
|
||||||
|
mediaType = "application/octet-stream"
|
||||||
|
}
|
||||||
|
log.Entry().Debugf("Using mediaType '%v'", mediaType)
|
||||||
|
|
||||||
|
name := filepath.Base(myGithubPublishReleaseOptions.AssetPath)
|
||||||
|
log.Entry().Debugf("Using file name '%v'", name)
|
||||||
|
|
||||||
|
opts := github.UploadOptions{
|
||||||
|
Name: name,
|
||||||
|
MediaType: mediaType,
|
||||||
|
}
|
||||||
|
file, err := os.Open(myGithubPublishReleaseOptions.AssetPath)
|
||||||
|
defer file.Close()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "Failed to load release asset '%v'", myGithubPublishReleaseOptions.AssetPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Entry().Info("Starting to upload release asset.")
|
||||||
|
asset, _, err := ghRepoClient.UploadReleaseAsset(ctx, myGithubPublishReleaseOptions.Owner, myGithubPublishReleaseOptions.Repository, releaseID, &opts, file)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "Failed to upload release asset.")
|
||||||
|
}
|
||||||
|
log.Entry().Infof("Done uploading asset '%v'.", asset.GetURL())
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isExcluded(issue *github.Issue, excludeLabels []string) bool {
|
||||||
|
//issue.Labels[0].GetName()
|
||||||
|
for _, ex := range excludeLabels {
|
||||||
|
for _, l := range issue.Labels {
|
||||||
|
if ex == l.GetName() {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
189
cmd/githubPublishRelease_generated.go
Normal file
189
cmd/githubPublishRelease_generated.go
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/SAP/jenkins-library/pkg/config"
|
||||||
|
"github.com/SAP/jenkins-library/pkg/log"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
type githubPublishReleaseOptions struct {
|
||||||
|
AddClosedIssues bool `json:"addClosedIssues,omitempty"`
|
||||||
|
AddDeltaToLastRelease bool `json:"addDeltaToLastRelease,omitempty"`
|
||||||
|
AssetPath string `json:"assetPath,omitempty"`
|
||||||
|
Commitish string `json:"commitish,omitempty"`
|
||||||
|
ExcludeLabels []string `json:"excludeLabels,omitempty"`
|
||||||
|
APIURL string `json:"apiUrl,omitempty"`
|
||||||
|
Owner string `json:"owner,omitempty"`
|
||||||
|
Repository string `json:"repository,omitempty"`
|
||||||
|
ServerURL string `json:"serverUrl,omitempty"`
|
||||||
|
Token string `json:"token,omitempty"`
|
||||||
|
UploadURL string `json:"uploadUrl,omitempty"`
|
||||||
|
Labels []string `json:"labels,omitempty"`
|
||||||
|
ReleaseBodyHeader string `json:"releaseBodyHeader,omitempty"`
|
||||||
|
UpdateAsset bool `json:"updateAsset,omitempty"`
|
||||||
|
Version string `json:"version,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var myGithubPublishReleaseOptions githubPublishReleaseOptions
|
||||||
|
var githubPublishReleaseStepConfigJSON string
|
||||||
|
|
||||||
|
// GithubPublishReleaseCommand Publish a release in GitHub
|
||||||
|
func GithubPublishReleaseCommand() *cobra.Command {
|
||||||
|
metadata := githubPublishReleaseMetadata()
|
||||||
|
var createGithubPublishReleaseCmd = &cobra.Command{
|
||||||
|
Use: "githubPublishRelease",
|
||||||
|
Short: "Publish a release in GitHub",
|
||||||
|
Long: `This step creates a tag in your GitHub repository together with a release.
|
||||||
|
The release can be filled with text plus additional information like:
|
||||||
|
|
||||||
|
* Closed pull request since last release
|
||||||
|
* Closed issues since last release
|
||||||
|
* Link to delta information showing all commits since last release
|
||||||
|
|
||||||
|
The result looks like
|
||||||
|
|
||||||
|
`,
|
||||||
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
log.SetStepName("githubPublishRelease")
|
||||||
|
log.SetVerbose(generalConfig.verbose)
|
||||||
|
return PrepareConfig(cmd, &metadata, "githubPublishRelease", &myGithubPublishReleaseOptions, openPiperFile)
|
||||||
|
},
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
return githubPublishRelease(myGithubPublishReleaseOptions)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
addGithubPublishReleaseFlags(createGithubPublishReleaseCmd)
|
||||||
|
return createGithubPublishReleaseCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
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.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.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().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().StringVar(&myGithubPublishReleaseOptions.Owner, "owner", os.Getenv("PIPER_owner"), "Set the GitHub organization.")
|
||||||
|
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.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().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().BoolVar(&myGithubPublishReleaseOptions.UpdateAsset, "updateAsset", false, "Specify if a release asset should be updated only.")
|
||||||
|
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("owner")
|
||||||
|
cmd.MarkFlagRequired("repository")
|
||||||
|
cmd.MarkFlagRequired("serverUrl")
|
||||||
|
cmd.MarkFlagRequired("token")
|
||||||
|
cmd.MarkFlagRequired("uploadUrl")
|
||||||
|
cmd.MarkFlagRequired("version")
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieve step metadata
|
||||||
|
func githubPublishReleaseMetadata() config.StepData {
|
||||||
|
var theMetaData = config.StepData{
|
||||||
|
Spec: config.StepSpec{
|
||||||
|
Inputs: config.StepInputs{
|
||||||
|
Parameters: []config.StepParameters{
|
||||||
|
{
|
||||||
|
Name: "addClosedIssues",
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "bool",
|
||||||
|
Mandatory: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "addDeltaToLastRelease",
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "bool",
|
||||||
|
Mandatory: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "assetPath",
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "commitish",
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "excludeLabels",
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "[]string",
|
||||||
|
Mandatory: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "apiUrl",
|
||||||
|
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "owner",
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "repository",
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "serverUrl",
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "token",
|
||||||
|
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "uploadUrl",
|
||||||
|
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "labels",
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "[]string",
|
||||||
|
Mandatory: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "releaseBodyHeader",
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "updateAsset",
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "bool",
|
||||||
|
Mandatory: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "version",
|
||||||
|
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||||
|
Type: "string",
|
||||||
|
Mandatory: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return theMetaData
|
||||||
|
}
|
16
cmd/githubPublishRelease_generated_test.go
Normal file
16
cmd/githubPublishRelease_generated_test.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGithubPublishReleaseCommand(t *testing.T) {
|
||||||
|
|
||||||
|
testCmd := GithubPublishReleaseCommand()
|
||||||
|
|
||||||
|
// only high level testing performed - details are tested in step generation procudure
|
||||||
|
assert.Equal(t, "githubPublishRelease", testCmd.Use, "command name incorrect")
|
||||||
|
|
||||||
|
}
|
383
cmd/githubPublishRelease_test.go
Normal file
383
cmd/githubPublishRelease_test.go
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v28/github"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ghRCMock struct {
|
||||||
|
createErr error
|
||||||
|
latestRelease *github.RepositoryRelease
|
||||||
|
release *github.RepositoryRelease
|
||||||
|
delErr error
|
||||||
|
delID int64
|
||||||
|
delOwner string
|
||||||
|
delRepo string
|
||||||
|
listErr error
|
||||||
|
listID int64
|
||||||
|
listOwner string
|
||||||
|
listReleaseAssets []*github.ReleaseAsset
|
||||||
|
listRepo string
|
||||||
|
listOpts *github.ListOptions
|
||||||
|
latestStatusCode int
|
||||||
|
latestErr error
|
||||||
|
uploadID int64
|
||||||
|
uploadOpts *github.UploadOptions
|
||||||
|
uploadOwner string
|
||||||
|
uploadRepo string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *ghRCMock) CreateRelease(ctx context.Context, owner string, repo string, release *github.RepositoryRelease) (*github.RepositoryRelease, *github.Response, error) {
|
||||||
|
g.release = release
|
||||||
|
return release, nil, g.createErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *ghRCMock) DeleteReleaseAsset(ctx context.Context, owner string, repo string, id int64) (*github.Response, error) {
|
||||||
|
g.delOwner = owner
|
||||||
|
g.delRepo = repo
|
||||||
|
g.delID = id
|
||||||
|
return nil, g.delErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *ghRCMock) GetLatestRelease(ctx context.Context, owner string, repo string) (*github.RepositoryRelease, *github.Response, error) {
|
||||||
|
hc := http.Response{StatusCode: 200}
|
||||||
|
if g.latestStatusCode != 0 {
|
||||||
|
hc.StatusCode = g.latestStatusCode
|
||||||
|
}
|
||||||
|
ghResp := github.Response{Response: &hc}
|
||||||
|
return g.latestRelease, &ghResp, g.latestErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *ghRCMock) ListReleaseAssets(ctx context.Context, owner string, repo string, id int64, opt *github.ListOptions) ([]*github.ReleaseAsset, *github.Response, error) {
|
||||||
|
g.listID = id
|
||||||
|
g.listOwner = owner
|
||||||
|
g.listRepo = repo
|
||||||
|
g.listOpts = opt
|
||||||
|
return g.listReleaseAssets, nil, g.listErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *ghRCMock) UploadReleaseAsset(ctx context.Context, owner string, repo string, id int64, opt *github.UploadOptions, file *os.File) (*github.ReleaseAsset, *github.Response, error) {
|
||||||
|
g.uploadID = id
|
||||||
|
g.uploadOwner = owner
|
||||||
|
g.uploadRepo = repo
|
||||||
|
g.uploadOpts = opt
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ghICMock struct {
|
||||||
|
issues []*github.Issue
|
||||||
|
lastPublished time.Time
|
||||||
|
owner string
|
||||||
|
repo string
|
||||||
|
options *github.IssueListByRepoOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *ghICMock) ListByRepo(ctx context.Context, owner string, repo string, opt *github.IssueListByRepoOptions) ([]*github.Issue, *github.Response, error) {
|
||||||
|
g.owner = owner
|
||||||
|
g.repo = repo
|
||||||
|
g.options = opt
|
||||||
|
g.lastPublished = opt.Since
|
||||||
|
return g.issues, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunGithubPublishRelease(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
t.Run("Success - first release & no body", func(t *testing.T) {
|
||||||
|
ghIssueClient := ghICMock{}
|
||||||
|
ghRepoClient := ghRCMock{
|
||||||
|
latestStatusCode: 404,
|
||||||
|
latestErr: fmt.Errorf("not found"),
|
||||||
|
}
|
||||||
|
|
||||||
|
myGithubPublishReleaseOptions := githubPublishReleaseOptions{
|
||||||
|
AddDeltaToLastRelease: true,
|
||||||
|
Commitish: "master",
|
||||||
|
Owner: "TEST",
|
||||||
|
Repository: "test",
|
||||||
|
ServerURL: "https://github.com",
|
||||||
|
ReleaseBodyHeader: "Header",
|
||||||
|
Version: "1.0",
|
||||||
|
}
|
||||||
|
err := runGithubPublishRelease(ctx, &myGithubPublishReleaseOptions, &ghRepoClient, &ghIssueClient)
|
||||||
|
assert.NoError(t, err, "Error occured but none expected.")
|
||||||
|
|
||||||
|
assert.Equal(t, "Header\n", ghRepoClient.release.GetBody())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Success - subsequent releases & with body", func(t *testing.T) {
|
||||||
|
lastTag := "1.0"
|
||||||
|
lastPublishedAt := github.Timestamp{Time: time.Date(2019, 01, 01, 0, 0, 0, 0, time.UTC)}
|
||||||
|
ghRepoClient := ghRCMock{
|
||||||
|
createErr: nil,
|
||||||
|
latestRelease: &github.RepositoryRelease{
|
||||||
|
TagName: &lastTag,
|
||||||
|
PublishedAt: &lastPublishedAt,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
prHTMLURL := "https://github.com/TEST/test/pull/1"
|
||||||
|
prTitle := "Pull"
|
||||||
|
prNo := 1
|
||||||
|
|
||||||
|
issHTMLURL := "https://github.com/TEST/test/issues/2"
|
||||||
|
issTitle := "Issue"
|
||||||
|
issNo := 2
|
||||||
|
|
||||||
|
ghIssueClient := ghICMock{
|
||||||
|
issues: []*github.Issue{
|
||||||
|
{Number: &prNo, Title: &prTitle, HTMLURL: &prHTMLURL, PullRequestLinks: &github.PullRequestLinks{URL: &prHTMLURL}},
|
||||||
|
{Number: &issNo, Title: &issTitle, HTMLURL: &issHTMLURL},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
myGithubPublishReleaseOptions := githubPublishReleaseOptions{
|
||||||
|
AddClosedIssues: true,
|
||||||
|
AddDeltaToLastRelease: true,
|
||||||
|
Commitish: "master",
|
||||||
|
Owner: "TEST",
|
||||||
|
Repository: "test",
|
||||||
|
ServerURL: "https://github.com",
|
||||||
|
ReleaseBodyHeader: "Header",
|
||||||
|
Version: "1.1",
|
||||||
|
}
|
||||||
|
err := runGithubPublishRelease(ctx, &myGithubPublishReleaseOptions, &ghRepoClient, &ghIssueClient)
|
||||||
|
|
||||||
|
assert.NoError(t, err, "Error occured but none expected.")
|
||||||
|
|
||||||
|
assert.Equal(t, "Header\n\n**List of closed pull-requests since last release**\n[#1](https://github.com/TEST/test/pull/1): Pull\n\n**List of closed issues since last release**\n[#2](https://github.com/TEST/test/issues/2): Issue\n\n**Changes**\n[1.0...1.1](https://github.com/TEST/test/compare/1.0...1.1)\n", ghRepoClient.release.GetBody())
|
||||||
|
assert.Equal(t, "1.1", ghRepoClient.release.GetName())
|
||||||
|
assert.Equal(t, "1.1", ghRepoClient.release.GetTagName())
|
||||||
|
assert.Equal(t, "master", ghRepoClient.release.GetTargetCommitish())
|
||||||
|
|
||||||
|
assert.Equal(t, lastPublishedAt.Time, ghIssueClient.lastPublished)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Success - update asset", func(t *testing.T) {
|
||||||
|
var releaseID int64 = 1
|
||||||
|
ghIssueClient := ghICMock{}
|
||||||
|
ghRepoClient := ghRCMock{
|
||||||
|
latestRelease: &github.RepositoryRelease{
|
||||||
|
ID: &releaseID,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
myGithubPublishReleaseOptions := githubPublishReleaseOptions{
|
||||||
|
UpdateAsset: true,
|
||||||
|
AssetPath: filepath.Join("testdata", t.Name()+"_test.txt"),
|
||||||
|
Version: "latest",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := runGithubPublishRelease(ctx, &myGithubPublishReleaseOptions, &ghRepoClient, &ghIssueClient)
|
||||||
|
|
||||||
|
assert.NoError(t, err, "Error occured but none expected.")
|
||||||
|
|
||||||
|
assert.Nil(t, ghRepoClient.release)
|
||||||
|
|
||||||
|
assert.Equal(t, releaseID, ghRepoClient.listID)
|
||||||
|
assert.Equal(t, releaseID, ghRepoClient.uploadID)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Error - get release", func(t *testing.T) {
|
||||||
|
ghIssueClient := ghICMock{}
|
||||||
|
ghRepoClient := ghRCMock{
|
||||||
|
latestErr: fmt.Errorf("Latest release error"),
|
||||||
|
}
|
||||||
|
myGithubPublishReleaseOptions := githubPublishReleaseOptions{}
|
||||||
|
err := runGithubPublishRelease(ctx, &myGithubPublishReleaseOptions, &ghRepoClient, &ghIssueClient)
|
||||||
|
|
||||||
|
assert.Equal(t, "Error occured when retrieving latest GitHub release.: Latest release error", fmt.Sprint(err))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Error - create release", func(t *testing.T) {
|
||||||
|
ghIssueClient := ghICMock{}
|
||||||
|
ghRepoClient := ghRCMock{
|
||||||
|
createErr: fmt.Errorf("Create release error"),
|
||||||
|
}
|
||||||
|
myGithubPublishReleaseOptions := githubPublishReleaseOptions{
|
||||||
|
Version: "1.0",
|
||||||
|
}
|
||||||
|
err := runGithubPublishRelease(ctx, &myGithubPublishReleaseOptions, &ghRepoClient, &ghIssueClient)
|
||||||
|
|
||||||
|
assert.Equal(t, "Creation of release '1.0' failed: Create release error", fmt.Sprint(err))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetClosedIssuesText(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
publishedAt := github.Timestamp{Time: time.Date(2019, 01, 01, 0, 0, 0, 0, time.UTC)}
|
||||||
|
|
||||||
|
t.Run("No issues", func(t *testing.T) {
|
||||||
|
ghIssueClient := ghICMock{}
|
||||||
|
myGithubPublishReleaseOptions := githubPublishReleaseOptions{
|
||||||
|
Version: "1.0",
|
||||||
|
}
|
||||||
|
|
||||||
|
res := getClosedIssuesText(ctx, publishedAt, &myGithubPublishReleaseOptions, &ghIssueClient)
|
||||||
|
|
||||||
|
assert.Equal(t, "", res)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("All issues", func(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
publishedAt := github.Timestamp{Time: time.Date(2019, 01, 01, 0, 0, 0, 0, time.UTC)}
|
||||||
|
|
||||||
|
prHTMLURL := []string{"https://github.com/TEST/test/pull/1", "https://github.com/TEST/test/pull/2"}
|
||||||
|
prTitle := []string{"Pull1", "Pull2"}
|
||||||
|
prNo := []int{1, 2}
|
||||||
|
|
||||||
|
issHTMLURL := []string{"https://github.com/TEST/test/issues/3", "https://github.com/TEST/test/issues/4"}
|
||||||
|
issTitle := []string{"Issue3", "Issue4"}
|
||||||
|
issNo := []int{3, 4}
|
||||||
|
|
||||||
|
ghIssueClient := ghICMock{
|
||||||
|
issues: []*github.Issue{
|
||||||
|
{Number: &prNo[0], Title: &prTitle[0], HTMLURL: &prHTMLURL[0], PullRequestLinks: &github.PullRequestLinks{URL: &prHTMLURL[0]}},
|
||||||
|
{Number: &prNo[1], Title: &prTitle[1], HTMLURL: &prHTMLURL[1], PullRequestLinks: &github.PullRequestLinks{URL: &prHTMLURL[1]}},
|
||||||
|
{Number: &issNo[0], Title: &issTitle[0], HTMLURL: &issHTMLURL[0]},
|
||||||
|
{Number: &issNo[1], Title: &issTitle[1], HTMLURL: &issHTMLURL[1]},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
myGithubPublishReleaseOptions := githubPublishReleaseOptions{
|
||||||
|
Owner: "TEST",
|
||||||
|
Repository: "test",
|
||||||
|
}
|
||||||
|
|
||||||
|
res := getClosedIssuesText(ctx, publishedAt, &myGithubPublishReleaseOptions, &ghIssueClient)
|
||||||
|
|
||||||
|
assert.Equal(t, "\n**List of closed pull-requests since last release**\n[#1](https://github.com/TEST/test/pull/1): Pull1\n[#2](https://github.com/TEST/test/pull/2): Pull2\n\n**List of closed issues since last release**\n[#3](https://github.com/TEST/test/issues/3): Issue3\n[#4](https://github.com/TEST/test/issues/4): Issue4\n", res)
|
||||||
|
assert.Equal(t, "TEST", ghIssueClient.owner, "Owner not properly passed")
|
||||||
|
assert.Equal(t, "test", ghIssueClient.repo, "Repo not properly passed")
|
||||||
|
assert.Equal(t, "closed", ghIssueClient.options.State, "Issue state not properly passed")
|
||||||
|
assert.Equal(t, "asc", ghIssueClient.options.Direction, "Sort direction not properly passed")
|
||||||
|
assert.Equal(t, publishedAt.Time, ghIssueClient.options.Since, "PublishedAt not properly passed")
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetReleaseDeltaText(t *testing.T) {
|
||||||
|
myGithubPublishReleaseOptions := githubPublishReleaseOptions{
|
||||||
|
Owner: "TEST",
|
||||||
|
Repository: "test",
|
||||||
|
ServerURL: "https://github.com",
|
||||||
|
Version: "1.1",
|
||||||
|
}
|
||||||
|
lastTag := "1.0"
|
||||||
|
lastRelease := github.RepositoryRelease{
|
||||||
|
TagName: &lastTag,
|
||||||
|
}
|
||||||
|
|
||||||
|
res := getReleaseDeltaText(&myGithubPublishReleaseOptions, &lastRelease)
|
||||||
|
|
||||||
|
assert.Equal(t, "\n**Changes**\n[1.0...1.1](https://github.com/TEST/test/compare/1.0...1.1)\n", res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUploadReleaseAsset(t *testing.T) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
t.Run("Success - existing asset", func(t *testing.T) {
|
||||||
|
var releaseID int64 = 1
|
||||||
|
assetName := "Success_-_existing_asset_test.txt"
|
||||||
|
var assetID int64 = 11
|
||||||
|
ghRepoClient := ghRCMock{
|
||||||
|
latestRelease: &github.RepositoryRelease{
|
||||||
|
ID: &releaseID,
|
||||||
|
},
|
||||||
|
listReleaseAssets: []*github.ReleaseAsset{
|
||||||
|
{Name: &assetName, ID: &assetID},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
myGithubPublishReleaseOptions := githubPublishReleaseOptions{
|
||||||
|
Owner: "TEST",
|
||||||
|
Repository: "test",
|
||||||
|
AssetPath: filepath.Join("testdata", t.Name()+"_test.txt"),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := uploadReleaseAsset(ctx, releaseID, &myGithubPublishReleaseOptions, &ghRepoClient)
|
||||||
|
|
||||||
|
assert.NoError(t, err, "Error occured but none expected.")
|
||||||
|
|
||||||
|
assert.Equal(t, "TEST", ghRepoClient.listOwner, "Owner not properly passed - list")
|
||||||
|
assert.Equal(t, "test", ghRepoClient.listRepo, "Repo not properly passed - list")
|
||||||
|
assert.Equal(t, releaseID, ghRepoClient.listID, "Relase ID not properly passed - list")
|
||||||
|
|
||||||
|
assert.Equal(t, "TEST", ghRepoClient.delOwner, "Owner not properly passed - del")
|
||||||
|
assert.Equal(t, "test", ghRepoClient.delRepo, "Repo not properly passed - del")
|
||||||
|
assert.Equal(t, assetID, ghRepoClient.delID, "Relase ID not properly passed - del")
|
||||||
|
|
||||||
|
assert.Equal(t, "TEST", ghRepoClient.uploadOwner, "Owner not properly passed - upload")
|
||||||
|
assert.Equal(t, "test", ghRepoClient.uploadRepo, "Repo not properly passed - upload")
|
||||||
|
assert.Equal(t, releaseID, ghRepoClient.uploadID, "Relase ID not properly passed - upload")
|
||||||
|
assert.Equal(t, "text/plain; charset=utf-8", ghRepoClient.uploadOpts.MediaType, "Wrong MediaType passed - upload")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Success - no asset", func(t *testing.T) {
|
||||||
|
var releaseID int64 = 1
|
||||||
|
assetName := "notFound"
|
||||||
|
var assetID int64 = 11
|
||||||
|
ghRepoClient := ghRCMock{
|
||||||
|
latestRelease: &github.RepositoryRelease{
|
||||||
|
ID: &releaseID,
|
||||||
|
},
|
||||||
|
listReleaseAssets: []*github.ReleaseAsset{
|
||||||
|
{Name: &assetName, ID: &assetID},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
myGithubPublishReleaseOptions := githubPublishReleaseOptions{
|
||||||
|
Owner: "TEST",
|
||||||
|
Repository: "test",
|
||||||
|
AssetPath: filepath.Join("testdata", t.Name()+"_test.txt"),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := uploadReleaseAsset(ctx, releaseID, &myGithubPublishReleaseOptions, &ghRepoClient)
|
||||||
|
|
||||||
|
assert.NoError(t, err, "Error occured but none expected.")
|
||||||
|
|
||||||
|
assert.Equal(t, int64(0), ghRepoClient.delID, "Relase ID should not be populated")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Error - List Assets", func(t *testing.T) {
|
||||||
|
var releaseID int64 = 1
|
||||||
|
ghRepoClient := ghRCMock{
|
||||||
|
listErr: fmt.Errorf("List Asset Error"),
|
||||||
|
}
|
||||||
|
myGithubPublishReleaseOptions := githubPublishReleaseOptions{}
|
||||||
|
|
||||||
|
err := uploadReleaseAsset(ctx, releaseID, &myGithubPublishReleaseOptions, &ghRepoClient)
|
||||||
|
assert.Equal(t, "Failed to get list of release assets.: List Asset Error", fmt.Sprint(err), "Wrong error received")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIsExcluded(t *testing.T) {
|
||||||
|
|
||||||
|
l1 := "label1"
|
||||||
|
l2 := "label2"
|
||||||
|
|
||||||
|
tt := []struct {
|
||||||
|
issue *github.Issue
|
||||||
|
excludeLabels []string
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{issue: nil, excludeLabels: nil, expected: false},
|
||||||
|
{issue: &github.Issue{}, excludeLabels: nil, expected: false},
|
||||||
|
{issue: &github.Issue{Labels: []github.Label{{Name: &l1}}}, excludeLabels: nil, expected: false},
|
||||||
|
{issue: &github.Issue{Labels: []github.Label{{Name: &l1}}}, excludeLabels: []string{"label0"}, expected: false},
|
||||||
|
{issue: &github.Issue{Labels: []github.Label{{Name: &l1}}}, excludeLabels: []string{"label1"}, expected: true},
|
||||||
|
{issue: &github.Issue{Labels: []github.Label{{Name: &l1}, {Name: &l2}}}, excludeLabels: []string{}, expected: false},
|
||||||
|
{issue: &github.Issue{Labels: []github.Label{{Name: &l1}, {Name: &l2}}}, excludeLabels: []string{"label1"}, expected: true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range tt {
|
||||||
|
assert.Equal(t, v.expected, isExcluded(v.issue, v.excludeLabels), fmt.Sprintf("Run %v failed", k))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,8 +1,6 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
//"os"
|
|
||||||
|
|
||||||
"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"
|
||||||
|
@ -41,6 +41,7 @@ func Execute() {
|
|||||||
rootCmd.AddCommand(ConfigCommand())
|
rootCmd.AddCommand(ConfigCommand())
|
||||||
rootCmd.AddCommand(VersionCommand())
|
rootCmd.AddCommand(VersionCommand())
|
||||||
rootCmd.AddCommand(KarmaExecuteTestsCommand())
|
rootCmd.AddCommand(KarmaExecuteTestsCommand())
|
||||||
|
rootCmd.AddCommand(GithubPublishReleaseCommand())
|
||||||
|
|
||||||
addRootFlags(rootCmd)
|
addRootFlags(rootCmd)
|
||||||
if err := rootCmd.Execute(); err != nil {
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
1
cmd/testdata/TestRunGithubPublishRelease/Success_-_update_asset_test.txt
vendored
Normal file
1
cmd/testdata/TestRunGithubPublishRelease/Success_-_update_asset_test.txt
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
TEST
|
1
cmd/testdata/TestUploadReleaseAsset/Success_-_existing_asset_test.txt
vendored
Normal file
1
cmd/testdata/TestUploadReleaseAsset/Success_-_existing_asset_test.txt
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
TEST
|
1
cmd/testdata/TestUploadReleaseAsset/Success_-_no_asset_test.txt
vendored
Normal file
1
cmd/testdata/TestUploadReleaseAsset/Success_-_no_asset_test.txt
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
TEST
|
@ -1,8 +1,6 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
//"os"
|
|
||||||
|
|
||||||
"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"
|
||||||
|
3
go.mod
3
go.mod
@ -4,9 +4,12 @@ go 1.13
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/ghodss/yaml v1.0.0
|
github.com/ghodss/yaml v1.0.0
|
||||||
|
github.com/google/go-github/v28 v28.1.1
|
||||||
|
github.com/google/go-cmp v0.3.1
|
||||||
github.com/pkg/errors v0.8.1
|
github.com/pkg/errors v0.8.1
|
||||||
github.com/sirupsen/logrus v1.4.2
|
github.com/sirupsen/logrus v1.4.2
|
||||||
github.com/spf13/cobra v0.0.5
|
github.com/spf13/cobra v0.0.5
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/stretchr/testify v1.2.2
|
github.com/stretchr/testify v1.2.2
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||||
)
|
)
|
||||||
|
24
go.sum
24
go.sum
@ -1,3 +1,4 @@
|
|||||||
|
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
@ -9,9 +10,18 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
|||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||||
|
github.com/google/go-github/v28 v28.1.1 h1:kORf5ekX5qwXO2mGzXXOjMe/g6ap8ahVe0sBEulhSxo=
|
||||||
|
github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM=
|
||||||
|
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||||
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
|
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||||
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
@ -39,10 +49,24 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
||||||
|
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||||
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc=
|
||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ghodss/yaml"
|
"github.com/ghodss/yaml"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -130,6 +131,22 @@ func (c *Config) GetStepConfig(flagValues map[string]interface{}, paramJSON stri
|
|||||||
stepConfig.mixIn(flagValues, filters.Parameters)
|
stepConfig.mixIn(flagValues, filters.Parameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// finally do the condition evaluation post processing
|
||||||
|
for _, p := range parameters {
|
||||||
|
if len(p.Conditions) > 0 {
|
||||||
|
cp := p.Conditions[0].Params[0]
|
||||||
|
dependentValue := stepConfig.Config[cp.Name]
|
||||||
|
if cmp.Equal(dependentValue, cp.Value) && stepConfig.Config[p.Name] == nil {
|
||||||
|
subMapValue := stepConfig.Config[dependentValue.(string)].(map[string]interface{})[p.Name]
|
||||||
|
if subMapValue != nil {
|
||||||
|
stepConfig.Config[p.Name] = subMapValue
|
||||||
|
} else {
|
||||||
|
stepConfig.Config[p.Name] = p.Default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return stepConfig, nil
|
return stepConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +194,7 @@ func (s *StepConfig) mixIn(mergeData map[string]interface{}, filter []string) {
|
|||||||
s.Config = map[string]interface{}{}
|
s.Config = map[string]interface{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Config = filterMap(merge(s.Config, mergeData), filter)
|
s.Config = merge(s.Config, filterMap(mergeData, filter))
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterMap(data map[string]interface{}, filter []string) map[string]interface{} {
|
func filterMap(data map[string]interface{}, filter []string) map[string]interface{} {
|
||||||
|
@ -74,6 +74,7 @@ steps:
|
|||||||
p4: p4_step
|
p4: p4_step
|
||||||
px4: px4_step
|
px4: px4_step
|
||||||
p5: p5_step
|
p5: p5_step
|
||||||
|
dependentParameter: dependentValue
|
||||||
stages:
|
stages:
|
||||||
stage1:
|
stage1:
|
||||||
p5: p5_stage
|
p5: p5_stage
|
||||||
@ -82,7 +83,7 @@ stages:
|
|||||||
`
|
`
|
||||||
filters := StepFilters{
|
filters := StepFilters{
|
||||||
General: []string{"p0", "p1", "p2", "p3", "p4"},
|
General: []string{"p0", "p1", "p2", "p3", "p4"},
|
||||||
Steps: []string{"p0", "p1", "p2", "p3", "p4", "p5"},
|
Steps: []string{"p0", "p1", "p2", "p3", "p4", "p5", "dependentParameter", "pd1", "dependentValue", "pd2"},
|
||||||
Stages: []string{"p0", "p1", "p2", "p3", "p4", "p5", "p6"},
|
Stages: []string{"p0", "p1", "p2", "p3", "p4", "p5", "p6"},
|
||||||
Parameters: []string{"p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7"},
|
Parameters: []string{"p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7"},
|
||||||
Env: []string{"p0", "p1", "p2", "p3", "p4", "p5"},
|
Env: []string{"p0", "p1", "p2", "p3", "p4", "p5"},
|
||||||
@ -97,6 +98,8 @@ steps:
|
|||||||
p1: p1_step_default
|
p1: p1_step_default
|
||||||
px1: px1_step_default
|
px1: px1_step_default
|
||||||
p2: p2_step_default
|
p2: p2_step_default
|
||||||
|
dependentValue:
|
||||||
|
pd1: pd1_dependent_default
|
||||||
`
|
`
|
||||||
|
|
||||||
defaults2 := `general:
|
defaults2 := `general:
|
||||||
@ -112,7 +115,34 @@ steps:
|
|||||||
defaults := []io.ReadCloser{ioutil.NopCloser(strings.NewReader(defaults1)), ioutil.NopCloser(strings.NewReader(defaults2))}
|
defaults := []io.ReadCloser{ioutil.NopCloser(strings.NewReader(defaults1)), ioutil.NopCloser(strings.NewReader(defaults2))}
|
||||||
|
|
||||||
myConfig := ioutil.NopCloser(strings.NewReader(testConfig))
|
myConfig := ioutil.NopCloser(strings.NewReader(testConfig))
|
||||||
stepConfig, err := c.GetStepConfig(flags, paramJSON, myConfig, defaults, filters, []StepParameters{}, "stage1", "step1")
|
|
||||||
|
parameterMetadata := []StepParameters{
|
||||||
|
{
|
||||||
|
Name: "pd1",
|
||||||
|
Scope: []string{"STEPS"},
|
||||||
|
Conditions: []Condition{
|
||||||
|
{
|
||||||
|
Params: []Param{
|
||||||
|
{Name: "dependentParameter", Value: "dependentValue"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "pd2",
|
||||||
|
Default: "pd2_metadata_default",
|
||||||
|
Scope: []string{"STEPS"},
|
||||||
|
Conditions: []Condition{
|
||||||
|
{
|
||||||
|
Params: []Param{
|
||||||
|
{Name: "dependentParameter", Value: "dependentValue"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
stepConfig, err := c.GetStepConfig(flags, paramJSON, myConfig, defaults, filters, parameterMetadata, "stage1", "step1")
|
||||||
|
|
||||||
assert.Equal(t, nil, err, "error occured but none expected")
|
assert.Equal(t, nil, err, "error occured but none expected")
|
||||||
|
|
||||||
@ -126,6 +156,8 @@ steps:
|
|||||||
"p5": "p5_stage",
|
"p5": "p5_stage",
|
||||||
"p6": "p6_param",
|
"p6": "p6_param",
|
||||||
"p7": "p7_flag",
|
"p7": "p7_flag",
|
||||||
|
"pd1": "pd1_dependent_default",
|
||||||
|
"pd2": "pd2_metadata_default",
|
||||||
}
|
}
|
||||||
for k, v := range expected {
|
for k, v := range expected {
|
||||||
t.Run(k, func(t *testing.T) {
|
t.Run(k, func(t *testing.T) {
|
||||||
|
@ -48,6 +48,7 @@ type StepParameters struct {
|
|||||||
Mandatory bool `json:"mandatory,omitempty"`
|
Mandatory bool `json:"mandatory,omitempty"`
|
||||||
Default interface{} `json:"default,omitempty"`
|
Default interface{} `json:"default,omitempty"`
|
||||||
Aliases []Alias `json:"aliases,omitempty"`
|
Aliases []Alias `json:"aliases,omitempty"`
|
||||||
|
Conditions []Condition `json:"conditions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alias defines a step input parameter alias
|
// Alias defines a step input parameter alias
|
||||||
@ -61,6 +62,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"`
|
||||||
|
Conditions []Condition `json:"conditions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// StepSecrets defines the secrets to be provided by the step context, e.g. Jenkins pipeline
|
// StepSecrets defines the secrets to be provided by the step context, e.g. Jenkins pipeline
|
||||||
@ -86,6 +88,7 @@ type Container struct {
|
|||||||
ReadyCommand string `json:"readyCommand"`
|
ReadyCommand string `json:"readyCommand"`
|
||||||
Shell string `json:"shell"`
|
Shell string `json:"shell"`
|
||||||
WorkingDir string `json:"workingDir"`
|
WorkingDir string `json:"workingDir"`
|
||||||
|
Conditions []Condition `json:"conditions,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnvVar defines an environment variable
|
// EnvVar defines an environment variable
|
||||||
@ -94,6 +97,18 @@ type EnvVar struct {
|
|||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Condition defines an condition which decides when the parameter, resource or container is valid
|
||||||
|
type Condition struct {
|
||||||
|
ConditionRef string `json:"conditionRef"`
|
||||||
|
Params []Param `json:"params"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Param defines the parameters serving as inputs to the condition
|
||||||
|
type Param struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
// StepFilters defines the filter parameters for the different sections
|
// StepFilters defines the filter parameters for the different sections
|
||||||
type StepFilters struct {
|
type StepFilters struct {
|
||||||
All []string
|
All []string
|
||||||
@ -123,19 +138,25 @@ func (m *StepData) ReadPipelineStepData(metadata io.ReadCloser) error {
|
|||||||
func (m *StepData) GetParameterFilters() StepFilters {
|
func (m *StepData) GetParameterFilters() StepFilters {
|
||||||
var filters StepFilters
|
var filters StepFilters
|
||||||
for _, param := range m.Spec.Inputs.Parameters {
|
for _, param := range m.Spec.Inputs.Parameters {
|
||||||
filters.All = append(filters.All, param.Name)
|
parameterKeys := []string{param.Name}
|
||||||
|
for _, condition := range param.Conditions {
|
||||||
|
for _, dependentParam := range condition.Params {
|
||||||
|
parameterKeys = append(parameterKeys, dependentParam.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filters.All = append(filters.All, parameterKeys...)
|
||||||
for _, scope := range param.Scope {
|
for _, scope := range param.Scope {
|
||||||
switch scope {
|
switch scope {
|
||||||
case "GENERAL":
|
case "GENERAL":
|
||||||
filters.General = append(filters.General, param.Name)
|
filters.General = append(filters.General, parameterKeys...)
|
||||||
case "STEPS":
|
case "STEPS":
|
||||||
filters.Steps = append(filters.Steps, param.Name)
|
filters.Steps = append(filters.Steps, parameterKeys...)
|
||||||
case "STAGES":
|
case "STAGES":
|
||||||
filters.Stages = append(filters.Stages, param.Name)
|
filters.Stages = append(filters.Stages, parameterKeys...)
|
||||||
case "PARAMETERS":
|
case "PARAMETERS":
|
||||||
filters.Parameters = append(filters.Parameters, param.Name)
|
filters.Parameters = append(filters.Parameters, parameterKeys...)
|
||||||
case "ENV":
|
case "ENV":
|
||||||
filters.Env = append(filters.Env, param.Name)
|
filters.Env = append(filters.Env, parameterKeys...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,7 +177,15 @@ func (m *StepData) GetContextParameterFilters() StepFilters {
|
|||||||
|
|
||||||
containerFilters := []string{}
|
containerFilters := []string{}
|
||||||
if len(m.Spec.Containers) > 0 {
|
if len(m.Spec.Containers) > 0 {
|
||||||
containerFilters = append(containerFilters, []string{"containerCommand", "containerShell", "dockerEnvVars", "dockerImage", "dockerOptions", "dockerPullImage", "dockerVolumeBind", "dockerWorkspace"}...)
|
parameterKeys := []string{"containerCommand", "containerShell", "dockerEnvVars", "dockerImage", "dockerOptions", "dockerPullImage", "dockerVolumeBind", "dockerWorkspace"}
|
||||||
|
for _, container := range m.Spec.Containers {
|
||||||
|
for _, condition := range container.Conditions {
|
||||||
|
for _, dependentParam := range condition.Params {
|
||||||
|
parameterKeys = append(parameterKeys, dependentParam.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
containerFilters = append(containerFilters, parameterKeys...)
|
||||||
}
|
}
|
||||||
if len(m.Spec.Sidecars) > 0 {
|
if len(m.Spec.Sidecars) > 0 {
|
||||||
//ToDo: support fallback for "dockerName" configuration property -> via aliasing?
|
//ToDo: support fallback for "dockerName" configuration property -> via aliasing?
|
||||||
@ -175,59 +204,93 @@ func (m *StepData) GetContextParameterFilters() StepFilters {
|
|||||||
// It only supports scenarios with one container and optionally one sidecar
|
// It only supports scenarios with one container and optionally one sidecar
|
||||||
func (m *StepData) GetContextDefaults(stepName string) (io.ReadCloser, error) {
|
func (m *StepData) GetContextDefaults(stepName string) (io.ReadCloser, error) {
|
||||||
|
|
||||||
p := map[string]interface{}{}
|
|
||||||
|
|
||||||
//ToDo error handling empty Containers/Sidecars
|
//ToDo error handling empty Containers/Sidecars
|
||||||
//ToDo handle empty Command
|
//ToDo handle empty Command
|
||||||
|
root := map[string]interface{}{}
|
||||||
if len(m.Spec.Containers) > 0 {
|
if len(m.Spec.Containers) > 0 {
|
||||||
if len(m.Spec.Containers[0].Command) > 0 {
|
for _, container := range m.Spec.Containers {
|
||||||
p["containerCommand"] = m.Spec.Containers[0].Command[0]
|
key := ""
|
||||||
|
if len(container.Conditions) > 0 {
|
||||||
|
key = container.Conditions[0].Params[0].Value
|
||||||
}
|
}
|
||||||
p["containerName"] = m.Spec.Containers[0].Name
|
p := map[string]interface{}{}
|
||||||
p["containerShell"] = m.Spec.Containers[0].Shell
|
if key != "" {
|
||||||
p["dockerEnvVars"] = envVarsAsStringSlice(m.Spec.Containers[0].EnvVars)
|
root[key] = p
|
||||||
p["dockerImage"] = m.Spec.Containers[0].Image
|
} else {
|
||||||
p["dockerName"] = m.Spec.Containers[0].Name
|
p = root
|
||||||
p["dockerPullImage"] = m.Spec.Containers[0].ImagePullPolicy != "Never"
|
}
|
||||||
p["dockerWorkspace"] = m.Spec.Containers[0].WorkingDir
|
if len(container.Command) > 0 {
|
||||||
|
p["containerCommand"] = container.Command[0]
|
||||||
|
}
|
||||||
|
p["containerName"] = container.Name
|
||||||
|
p["containerShell"] = container.Shell
|
||||||
|
p["dockerEnvVars"] = envVarsAsStringSlice(container.EnvVars)
|
||||||
|
p["dockerImage"] = container.Image
|
||||||
|
p["dockerName"] = container.Name
|
||||||
|
p["dockerPullImage"] = container.ImagePullPolicy != "Never"
|
||||||
|
p["dockerWorkspace"] = container.WorkingDir
|
||||||
|
|
||||||
// Ready command not relevant for main runtime container so far
|
// Ready command not relevant for main runtime container so far
|
||||||
//p[] = m.Spec.Containers[0].ReadyCommand
|
//p[] = container.ReadyCommand
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(m.Spec.Sidecars) > 0 {
|
if len(m.Spec.Sidecars) > 0 {
|
||||||
if len(m.Spec.Sidecars[0].Command) > 0 {
|
if len(m.Spec.Sidecars[0].Command) > 0 {
|
||||||
p["sidecarCommand"] = m.Spec.Sidecars[0].Command[0]
|
root["sidecarCommand"] = m.Spec.Sidecars[0].Command[0]
|
||||||
}
|
}
|
||||||
p["sidecarEnvVars"] = envVarsAsStringSlice(m.Spec.Sidecars[0].EnvVars)
|
root["sidecarEnvVars"] = envVarsAsStringSlice(m.Spec.Sidecars[0].EnvVars)
|
||||||
p["sidecarImage"] = m.Spec.Sidecars[0].Image
|
root["sidecarImage"] = m.Spec.Sidecars[0].Image
|
||||||
p["sidecarName"] = m.Spec.Sidecars[0].Name
|
root["sidecarName"] = m.Spec.Sidecars[0].Name
|
||||||
p["sidecarPullImage"] = m.Spec.Sidecars[0].ImagePullPolicy != "Never"
|
root["sidecarPullImage"] = m.Spec.Sidecars[0].ImagePullPolicy != "Never"
|
||||||
p["sidecarReadyCommand"] = m.Spec.Sidecars[0].ReadyCommand
|
root["sidecarReadyCommand"] = m.Spec.Sidecars[0].ReadyCommand
|
||||||
p["sidecarWorkspace"] = m.Spec.Sidecars[0].WorkingDir
|
root["sidecarWorkspace"] = m.Spec.Sidecars[0].WorkingDir
|
||||||
}
|
}
|
||||||
|
|
||||||
// not filled for now since this is not relevant in Kubernetes case
|
// not filled for now since this is not relevant in Kubernetes case
|
||||||
//p["dockerOptions"] = m.Spec.Containers[0].
|
//p["dockerOptions"] = container.
|
||||||
//p["dockerVolumeBind"] = m.Spec.Containers[0].
|
//p["dockerVolumeBind"] = container.
|
||||||
//p["containerPortMappings"] = m.Spec.Sidecars[0].
|
//root["containerPortMappings"] = m.Spec.Sidecars[0].
|
||||||
//p["sidecarOptions"] = m.Spec.Sidecars[0].
|
//root["sidecarOptions"] = m.Spec.Sidecars[0].
|
||||||
//p["sidecarVolumeBind"] = m.Spec.Sidecars[0].
|
//root["sidecarVolumeBind"] = m.Spec.Sidecars[0].
|
||||||
|
|
||||||
if len(m.Spec.Inputs.Resources) > 0 {
|
if len(m.Spec.Inputs.Resources) > 0 {
|
||||||
var resources []string
|
keys := []string{}
|
||||||
|
resources := map[string][]string{}
|
||||||
for _, resource := range m.Spec.Inputs.Resources {
|
for _, resource := range m.Spec.Inputs.Resources {
|
||||||
if resource.Type == "stash" {
|
if resource.Type == "stash" {
|
||||||
resources = append(resources, resource.Name)
|
key := ""
|
||||||
|
if len(resource.Conditions) > 0 {
|
||||||
|
key = resource.Conditions[0].Params[0].Value
|
||||||
|
}
|
||||||
|
if resources[key] == nil {
|
||||||
|
keys = append(keys, key)
|
||||||
|
resources[key] = []string{}
|
||||||
|
}
|
||||||
|
resources[key] = append(resources[key], resource.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range keys {
|
||||||
|
if key == "" {
|
||||||
|
root["stashContent"] = resources[""]
|
||||||
|
} else {
|
||||||
|
if root[key] == nil {
|
||||||
|
root[key] = map[string]interface{}{
|
||||||
|
"stashContent": resources[key],
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p := root[key].(map[string]interface{})
|
||||||
|
p["stashContent"] = resources[key]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p["stashContent"] = resources
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c := Config{
|
c := Config{
|
||||||
Steps: map[string]map[string]interface{}{
|
Steps: map[string]map[string]interface{}{
|
||||||
stepName: p,
|
stepName: root,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +68,7 @@ func TestGetParameterFilters(t *testing.T) {
|
|||||||
{Name: "paramFour", Scope: []string{"PARAMETERS", "ENV"}},
|
{Name: "paramFour", Scope: []string{"PARAMETERS", "ENV"}},
|
||||||
{Name: "paramFive", Scope: []string{"ENV"}},
|
{Name: "paramFive", Scope: []string{"ENV"}},
|
||||||
{Name: "paramSix"},
|
{Name: "paramSix"},
|
||||||
|
{Name: "paramSeven", Scope: []string{"GENERAL", "STEPS", "STAGES", "PARAMETERS"}, Conditions: []Condition{{Params: []Param{{Name: "buildTool", Value: "mta"}}}}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -113,17 +114,17 @@ func TestGetParameterFilters(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
Metadata: metadata1,
|
Metadata: metadata1,
|
||||||
ExpectedGeneral: []string{"paramOne"},
|
ExpectedGeneral: []string{"paramOne", "paramSeven", "mta"},
|
||||||
ExpectedSteps: []string{"paramOne", "paramTwo"},
|
ExpectedSteps: []string{"paramOne", "paramTwo", "paramSeven", "mta"},
|
||||||
ExpectedStages: []string{"paramOne", "paramTwo", "paramThree"},
|
ExpectedStages: []string{"paramOne", "paramTwo", "paramThree", "paramSeven", "mta"},
|
||||||
ExpectedParameters: []string{"paramOne", "paramTwo", "paramThree", "paramFour"},
|
ExpectedParameters: []string{"paramOne", "paramTwo", "paramThree", "paramFour", "paramSeven", "mta"},
|
||||||
ExpectedEnv: []string{"paramOne", "paramTwo", "paramThree", "paramFour", "paramFive"},
|
ExpectedEnv: []string{"paramOne", "paramTwo", "paramThree", "paramFour", "paramFive", "paramSeven", "mta"},
|
||||||
ExpectedAll: []string{"paramOne", "paramTwo", "paramThree", "paramFour", "paramFive", "paramSix"},
|
ExpectedAll: []string{"paramOne", "paramTwo", "paramThree", "paramFour", "paramFive", "paramSix", "paramSeven", "mta"},
|
||||||
NotExpectedGeneral: []string{"paramTwo", "paramThree", "paramFour", "paramFive", "paramSix"},
|
NotExpectedGeneral: []string{"paramTwo", "paramThree", "paramFour", "paramFive", "paramSix"},
|
||||||
NotExpectedSteps: []string{"paramThree", "paramFour", "paramFive", "paramSix"},
|
NotExpectedSteps: []string{"paramThree", "paramFour", "paramFive", "paramSix"},
|
||||||
NotExpectedStages: []string{"paramFour", "paramFive", "paramSix"},
|
NotExpectedStages: []string{"paramFour", "paramFive", "paramSix"},
|
||||||
NotExpectedParameters: []string{"paramFive", "paramSix"},
|
NotExpectedParameters: []string{"paramFive", "paramSix"},
|
||||||
NotExpectedEnv: []string{"paramSix"},
|
NotExpectedEnv: []string{"paramSix", "mta"},
|
||||||
NotExpectedAll: []string{},
|
NotExpectedAll: []string{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -234,6 +235,11 @@ func TestGetContextParameterFilters(t *testing.T) {
|
|||||||
Spec: StepSpec{
|
Spec: StepSpec{
|
||||||
Containers: []Container{
|
Containers: []Container{
|
||||||
{Name: "testcontainer"},
|
{Name: "testcontainer"},
|
||||||
|
{Conditions: []Condition{
|
||||||
|
{Params: []Param{
|
||||||
|
{Name: "scanType", Value: "pip"},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -258,12 +264,12 @@ func TestGetContextParameterFilters(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Containers", func(t *testing.T) {
|
t.Run("Containers", func(t *testing.T) {
|
||||||
filters := metadata2.GetContextParameterFilters()
|
filters := metadata2.GetContextParameterFilters()
|
||||||
assert.Equal(t, []string{"containerCommand", "containerShell", "dockerEnvVars", "dockerImage", "dockerOptions", "dockerPullImage", "dockerVolumeBind", "dockerWorkspace"}, filters.All, "incorrect filter All")
|
assert.Equal(t, []string{"containerCommand", "containerShell", "dockerEnvVars", "dockerImage", "dockerOptions", "dockerPullImage", "dockerVolumeBind", "dockerWorkspace", "pip"}, filters.All, "incorrect filter All")
|
||||||
assert.NotEqual(t, []string{"containerCommand", "containerShell", "dockerEnvVars", "dockerImage", "dockerOptions", "dockerPullImage", "dockerVolumeBind", "dockerWorkspace"}, filters.General, "incorrect filter General")
|
assert.NotEqual(t, []string{"containerCommand", "containerShell", "dockerEnvVars", "dockerImage", "dockerOptions", "dockerPullImage", "dockerVolumeBind", "dockerWorkspace", "pip"}, filters.General, "incorrect filter General")
|
||||||
assert.Equal(t, []string{"containerCommand", "containerShell", "dockerEnvVars", "dockerImage", "dockerOptions", "dockerPullImage", "dockerVolumeBind", "dockerWorkspace"}, filters.Steps, "incorrect filter Steps")
|
assert.Equal(t, []string{"containerCommand", "containerShell", "dockerEnvVars", "dockerImage", "dockerOptions", "dockerPullImage", "dockerVolumeBind", "dockerWorkspace", "pip"}, filters.Steps, "incorrect filter Steps")
|
||||||
assert.Equal(t, []string{"containerCommand", "containerShell", "dockerEnvVars", "dockerImage", "dockerOptions", "dockerPullImage", "dockerVolumeBind", "dockerWorkspace"}, filters.Stages, "incorrect filter Stages")
|
assert.Equal(t, []string{"containerCommand", "containerShell", "dockerEnvVars", "dockerImage", "dockerOptions", "dockerPullImage", "dockerVolumeBind", "dockerWorkspace", "pip"}, filters.Stages, "incorrect filter Stages")
|
||||||
assert.Equal(t, []string{"containerCommand", "containerShell", "dockerEnvVars", "dockerImage", "dockerOptions", "dockerPullImage", "dockerVolumeBind", "dockerWorkspace"}, filters.Parameters, "incorrect filter Parameters")
|
assert.Equal(t, []string{"containerCommand", "containerShell", "dockerEnvVars", "dockerImage", "dockerOptions", "dockerPullImage", "dockerVolumeBind", "dockerWorkspace", "pip"}, filters.Parameters, "incorrect filter Parameters")
|
||||||
assert.NotEqual(t, []string{"containerCommand", "containerShell", "dockerEnvVars", "dockerImage", "dockerOptions", "dockerPullImage", "dockerVolumeBind", "dockerWorkspace"}, filters.Env, "incorrect filter Env")
|
assert.NotEqual(t, []string{"containerCommand", "containerShell", "dockerEnvVars", "dockerImage", "dockerOptions", "dockerPullImage", "dockerVolumeBind", "dockerWorkspace", "pip"}, filters.Env, "incorrect filter Env")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Sidecars", func(t *testing.T) {
|
t.Run("Sidecars", func(t *testing.T) {
|
||||||
@ -287,15 +293,38 @@ func TestGetContextDefaults(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Name: "buildDescriptor",
|
Name: "buildDescriptor",
|
||||||
Type: "stash",
|
Type: "stash",
|
||||||
|
Conditions: []Condition{
|
||||||
|
{Params: []Param{
|
||||||
|
{Name: "scanType", Value: "abc"},
|
||||||
|
}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "source",
|
Name: "source",
|
||||||
Type: "stash",
|
Type: "stash",
|
||||||
|
Conditions: []Condition{
|
||||||
|
{Params: []Param{
|
||||||
|
{Name: "scanType", Value: "abc"},
|
||||||
|
}},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "test",
|
Name: "test",
|
||||||
Type: "nonce",
|
Type: "nonce",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "test2",
|
||||||
|
Type: "stash",
|
||||||
|
Conditions: []Condition{
|
||||||
|
{Params: []Param{
|
||||||
|
{Name: "scanType", Value: "def"},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "test3",
|
||||||
|
Type: "stash",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Containers: []Container{
|
Containers: []Container{
|
||||||
@ -339,7 +368,9 @@ func TestGetContextDefaults(t *testing.T) {
|
|||||||
var d PipelineDefaults
|
var d PipelineDefaults
|
||||||
d.ReadPipelineDefaults([]io.ReadCloser{cd})
|
d.ReadPipelineDefaults([]io.ReadCloser{cd})
|
||||||
|
|
||||||
assert.Equal(t, []interface{}{"buildDescriptor", "source"}, d.Defaults[0].Steps["testStep"]["stashContent"], "stashContent default not available")
|
assert.Equal(t, []interface{}{"buildDescriptor", "source"}, d.Defaults[0].Steps["testStep"]["abc"].(map[string]interface{})["stashContent"], "stashContent default not available")
|
||||||
|
assert.Equal(t, []interface{}{"test2"}, d.Defaults[0].Steps["testStep"]["def"].(map[string]interface{})["stashContent"], "stashContent default not available")
|
||||||
|
assert.Equal(t, []interface{}{"test3"}, d.Defaults[0].Steps["testStep"]["stashContent"], "stashContent default not available")
|
||||||
assert.Equal(t, "test/command", d.Defaults[0].Steps["testStep"]["containerCommand"], "containerCommand default not available")
|
assert.Equal(t, "test/command", d.Defaults[0].Steps["testStep"]["containerCommand"], "containerCommand default not available")
|
||||||
assert.Equal(t, "testcontainer", d.Defaults[0].Steps["testStep"]["containerName"], "containerName default not available")
|
assert.Equal(t, "testcontainer", d.Defaults[0].Steps["testStep"]["containerName"], "containerName default not available")
|
||||||
assert.Equal(t, "/bin/bash", d.Defaults[0].Steps["testStep"]["containerShell"], "containerShell default not available")
|
assert.Equal(t, "/bin/bash", d.Defaults[0].Steps["testStep"]["containerShell"], "containerShell default not available")
|
||||||
|
@ -30,7 +30,7 @@ type stepInfo struct {
|
|||||||
const stepGoTemplate = `package cmd
|
const stepGoTemplate = `package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
//"os"
|
{{if .OSImport}}"os"{{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"
|
||||||
@ -148,10 +148,11 @@ func processMetaFiles(metadataFiles []string, openFile func(s string) (io.ReadCl
|
|||||||
|
|
||||||
fmt.Printf("Step name: %v\n", stepData.Metadata.Name)
|
fmt.Printf("Step name: %v\n", stepData.Metadata.Name)
|
||||||
|
|
||||||
err = setDefaultParameters(&stepData)
|
osImport := false
|
||||||
|
osImport, err = setDefaultParameters(&stepData)
|
||||||
checkError(err)
|
checkError(err)
|
||||||
|
|
||||||
myStepInfo := getStepInfo(&stepData)
|
myStepInfo := getStepInfo(&stepData, osImport)
|
||||||
|
|
||||||
step := stepTemplate(myStepInfo)
|
step := stepTemplate(myStepInfo)
|
||||||
err = writeFile(fmt.Sprintf("cmd/%v_generated.go", stepData.Metadata.Name), step, 0644)
|
err = writeFile(fmt.Sprintf("cmd/%v_generated.go", stepData.Metadata.Name), step, 0644)
|
||||||
@ -172,14 +173,16 @@ func fileWriter(filename string, data []byte, perm os.FileMode) error {
|
|||||||
return ioutil.WriteFile(filename, data, perm)
|
return ioutil.WriteFile(filename, data, perm)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setDefaultParameters(stepData *config.StepData) error {
|
func setDefaultParameters(stepData *config.StepData) (bool, error) {
|
||||||
//ToDo: custom function for default handling, support all relevant parameter types
|
//ToDo: custom function for default handling, support all relevant parameter types
|
||||||
|
osImportRequired := false
|
||||||
for k, param := range stepData.Spec.Inputs.Parameters {
|
for k, param := range stepData.Spec.Inputs.Parameters {
|
||||||
|
|
||||||
if param.Default == nil {
|
if param.Default == nil {
|
||||||
switch param.Type {
|
switch param.Type {
|
||||||
case "string":
|
case "string":
|
||||||
param.Default = fmt.Sprintf("os.Getenv(\"PIPER_%v\")", param.Name)
|
param.Default = fmt.Sprintf("os.Getenv(\"PIPER_%v\")", param.Name)
|
||||||
|
osImportRequired = true
|
||||||
case "bool":
|
case "bool":
|
||||||
// ToDo: Check if default should be read from env
|
// ToDo: Check if default should be read from env
|
||||||
param.Default = "false"
|
param.Default = "false"
|
||||||
@ -187,7 +190,7 @@ func setDefaultParameters(stepData *config.StepData) error {
|
|||||||
// ToDo: Check if default should be read from env
|
// ToDo: Check if default should be read from env
|
||||||
param.Default = "[]string{}"
|
param.Default = "[]string{}"
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Meta data type not set or not known: '%v'", param.Type)
|
return false, fmt.Errorf("Meta data type not set or not known: '%v'", param.Type)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch param.Type {
|
switch param.Type {
|
||||||
@ -202,16 +205,16 @@ func setDefaultParameters(stepData *config.StepData) error {
|
|||||||
case "[]string":
|
case "[]string":
|
||||||
param.Default = fmt.Sprintf("[]string{\"%v\"}", strings.Join(param.Default.([]string), "\", \""))
|
param.Default = fmt.Sprintf("[]string{\"%v\"}", strings.Join(param.Default.([]string), "\", \""))
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Meta data type not set or not known: '%v'", param.Type)
|
return false, fmt.Errorf("Meta data type not set or not known: '%v'", param.Type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stepData.Spec.Inputs.Parameters[k] = param
|
stepData.Spec.Inputs.Parameters[k] = param
|
||||||
}
|
}
|
||||||
return nil
|
return osImportRequired, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getStepInfo(stepData *config.StepData) stepInfo {
|
func getStepInfo(stepData *config.StepData, osImport bool) stepInfo {
|
||||||
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)),
|
||||||
@ -220,6 +223,7 @@ func getStepInfo(stepData *config.StepData) stepInfo {
|
|||||||
Long: stepData.Metadata.LongDescription,
|
Long: stepData.Metadata.LongDescription,
|
||||||
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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,6 +295,7 @@ func longName(long string) string {
|
|||||||
|
|
||||||
func golangName(name string) string {
|
func golangName(name string) string {
|
||||||
properName := strings.Replace(name, "Api", "API", -1)
|
properName := strings.Replace(name, "Api", "API", -1)
|
||||||
|
properName = strings.Replace(properName, "api", "API", -1)
|
||||||
properName = strings.Replace(properName, "Url", "URL", -1)
|
properName = strings.Replace(properName, "Url", "URL", -1)
|
||||||
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)
|
||||||
|
@ -112,10 +112,12 @@ func TestSetDefaultParameters(t *testing.T) {
|
|||||||
"[]string{}",
|
"[]string{}",
|
||||||
}
|
}
|
||||||
|
|
||||||
err := setDefaultParameters(&stepData)
|
osImport, err := setDefaultParameters(&stepData)
|
||||||
|
|
||||||
assert.NoError(t, err, "error occured but none expected")
|
assert.NoError(t, err, "error occured but none expected")
|
||||||
|
|
||||||
|
assert.Equal(t, true, osImport, "import of os package required")
|
||||||
|
|
||||||
for k, v := range expected {
|
for k, v := range expected {
|
||||||
assert.Equal(t, v, stepData.Spec.Inputs.Parameters[k].Default, fmt.Sprintf("default not correct for parameter %v", k))
|
assert.Equal(t, v, stepData.Spec.Inputs.Parameters[k].Default, fmt.Sprintf("default not correct for parameter %v", k))
|
||||||
}
|
}
|
||||||
@ -145,7 +147,7 @@ func TestSetDefaultParameters(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range stepData {
|
for k, v := range stepData {
|
||||||
err := setDefaultParameters(&v)
|
_, err := setDefaultParameters(&v)
|
||||||
assert.Error(t, err, fmt.Sprintf("error expected but none occured for parameter %v", k))
|
assert.Error(t, err, fmt.Sprintf("error expected but none occured for parameter %v", k))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -168,7 +170,7 @@ func TestGetStepInfo(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
myStepInfo := getStepInfo(&stepData)
|
myStepInfo := getStepInfo(&stepData, true)
|
||||||
|
|
||||||
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")
|
||||||
@ -177,6 +179,7 @@ func TestGetStepInfo(t *testing.T) {
|
|||||||
assert.Equal(t, "Long Test description", myStepInfo.Long, "Long incorrect")
|
assert.Equal(t, "Long Test description", myStepInfo.Long, "Long incorrect")
|
||||||
assert.Equal(t, stepData.Spec.Inputs.Parameters, myStepInfo.Metadata, "Metadata incorrect")
|
assert.Equal(t, stepData.Spec.Inputs.Parameters, myStepInfo.Metadata, "Metadata incorrect")
|
||||||
assert.Equal(t, "addTestStepFlags", myStepInfo.FlagsFunc, "FlagsFunc incorrect")
|
assert.Equal(t, "addTestStepFlags", myStepInfo.FlagsFunc, "FlagsFunc incorrect")
|
||||||
|
assert.Equal(t, "addTestStepFlags", myStepInfo.FlagsFunc, "FlagsFunc incorrect")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,6 +203,7 @@ func TestGolangName(t *testing.T) {
|
|||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
{input: "testApi", expected: "TestAPI"},
|
{input: "testApi", expected: "TestAPI"},
|
||||||
|
{input: "apiTest", expected: "APITest"},
|
||||||
{input: "testUrl", expected: "TestURL"},
|
{input: "testUrl", expected: "TestURL"},
|
||||||
{input: "testId", expected: "TestID"},
|
{input: "testId", expected: "TestID"},
|
||||||
{input: "testJson", expected: "TestJSON"},
|
{input: "testJson", expected: "TestJSON"},
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
//"os"
|
"os"
|
||||||
|
|
||||||
"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"
|
||||||
|
23
pkg/github/github.go
Normal file
23
pkg/github/github.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package github
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/google/go-github/v28/github"
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
//NewClient creates a new GitHub client using an OAuth token for authentication
|
||||||
|
func NewClient(token, apiURL, uploadURL string) (context.Context, *github.Client, error) {
|
||||||
|
ctx := context.Background()
|
||||||
|
ts := oauth2.StaticTokenSource(
|
||||||
|
&oauth2.Token{AccessToken: token},
|
||||||
|
)
|
||||||
|
tc := oauth2.NewClient(ctx, ts)
|
||||||
|
|
||||||
|
client, err := github.NewEnterpriseClient(apiURL, uploadURL, tc)
|
||||||
|
if err != nil {
|
||||||
|
return ctx, nil, err
|
||||||
|
}
|
||||||
|
return ctx, client, nil
|
||||||
|
}
|
154
resources/metadata/githubrelease.yaml
Normal file
154
resources/metadata/githubrelease.yaml
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
metadata:
|
||||||
|
name: githubPublishRelease
|
||||||
|
description: Publish a release in GitHub
|
||||||
|
longDescription: |
|
||||||
|
This step creates a tag in your GitHub repository together with a release.
|
||||||
|
The release can be filled with text plus additional information like:
|
||||||
|
|
||||||
|
* Closed pull request since last release
|
||||||
|
* Closed issues since last release
|
||||||
|
* Link to delta information showing all commits since last release
|
||||||
|
|
||||||
|
The result looks like
|
||||||
|
|
||||||
|

|
||||||
|
spec:
|
||||||
|
inputs:
|
||||||
|
secrets:
|
||||||
|
- name: githubTokenCredentialsId
|
||||||
|
description: Jenkins 'Secret text' credentials ID containing token to authenticate to GitHub.
|
||||||
|
type: jenkins
|
||||||
|
params:
|
||||||
|
- name: addClosedIssues
|
||||||
|
description: 'If set to `true`, closed issues and merged pull-requests since the last release will added below the `releaseBodyHeader`'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
- name: addDeltaToLastRelease
|
||||||
|
description: 'If set to `true`, a link will be added to the relese information that brings up all commits since the last release.'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
- name: assetPath
|
||||||
|
description: Path to a release asset which should be uploaded to the list of release assets.
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: string
|
||||||
|
- name: commitish
|
||||||
|
description: 'Target git commitish for the release'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: string
|
||||||
|
default: "master"
|
||||||
|
- name: excludeLabels
|
||||||
|
description: 'Allows to exclude issues with dedicated list of labels.'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: '[]string'
|
||||||
|
- 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: owner
|
||||||
|
aliases:
|
||||||
|
- name: githubOrg
|
||||||
|
description: 'Set the GitHub organization.'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: string
|
||||||
|
mandatory: true
|
||||||
|
- name: repository
|
||||||
|
aliases:
|
||||||
|
- name: githubRepo
|
||||||
|
description: 'Set the GitHub repository.'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: string
|
||||||
|
mandatory: true
|
||||||
|
- name: serverUrl
|
||||||
|
aliases:
|
||||||
|
- name: githubServerUrl
|
||||||
|
description: 'GitHub server url for end-user access.'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: string
|
||||||
|
default: https://github.com
|
||||||
|
mandatory: true
|
||||||
|
- name: token
|
||||||
|
aliases:
|
||||||
|
- name: githubToken
|
||||||
|
description: 'GitHub personal access token as per https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line'
|
||||||
|
scope:
|
||||||
|
- GENERAL
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: string
|
||||||
|
mandatory: true
|
||||||
|
- name: uploadUrl
|
||||||
|
aliases:
|
||||||
|
- name: githubUploadUrl
|
||||||
|
description: Set the GitHub API url.
|
||||||
|
scope:
|
||||||
|
- GENERAL
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: string
|
||||||
|
default: https://uploads.github.com
|
||||||
|
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: updateAsset
|
||||||
|
description: Specify if a release asset should be updated only.
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: bool
|
||||||
|
- name: version
|
||||||
|
description: 'Define the version number which will be written as tag as well as release name.'
|
||||||
|
scope:
|
||||||
|
- PARAMETERS
|
||||||
|
- STAGES
|
||||||
|
- STEPS
|
||||||
|
type: string
|
||||||
|
mandatory: true
|
@ -7,6 +7,7 @@ import hudson.tasks.junit.TestResultAction
|
|||||||
import jenkins.model.Jenkins
|
import jenkins.model.Jenkins
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils
|
import org.apache.commons.io.IOUtils
|
||||||
|
import org.jenkinsci.plugins.workflow.libs.LibrariesAction
|
||||||
import org.jenkinsci.plugins.workflow.steps.MissingContextVariableException
|
import org.jenkinsci.plugins.workflow.steps.MissingContextVariableException
|
||||||
|
|
||||||
@API
|
@API
|
||||||
@ -108,3 +109,21 @@ String getIssueCommentTriggerAction() {
|
|||||||
def getJobStartedByUserId() {
|
def getJobStartedByUserId() {
|
||||||
return getRawBuild().getCause(hudson.model.Cause.UserIdCause.class)?.getUserId()
|
return getRawBuild().getCause(hudson.model.Cause.UserIdCause.class)?.getUserId()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonCPS
|
||||||
|
def getLibrariesInfo() {
|
||||||
|
def libraries = []
|
||||||
|
def build = getRawBuild()
|
||||||
|
def libs = build.getAction(LibrariesAction.class).getLibraries()
|
||||||
|
|
||||||
|
for (def i = 0; i < libs.size(); i++) {
|
||||||
|
Map lib = [:]
|
||||||
|
|
||||||
|
lib['name'] = libs[i].name
|
||||||
|
lib['version'] = libs[i].version
|
||||||
|
lib['trusted'] = libs[i].trusted
|
||||||
|
libraries.add(lib)
|
||||||
|
}
|
||||||
|
|
||||||
|
return libraries
|
||||||
|
}
|
||||||
|
63
src/com/sap/piper/PiperGoUtils.groovy
Normal file
63
src/com/sap/piper/PiperGoUtils.groovy
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package com.sap.piper
|
||||||
|
|
||||||
|
class PiperGoUtils implements Serializable {
|
||||||
|
|
||||||
|
private static Script steps
|
||||||
|
private static Utils utils
|
||||||
|
|
||||||
|
PiperGoUtils(Script steps) {
|
||||||
|
this.steps = steps
|
||||||
|
this.utils = new Utils()
|
||||||
|
}
|
||||||
|
|
||||||
|
PiperGoUtils(Script steps, Utils utils) {
|
||||||
|
this.steps = steps
|
||||||
|
this.utils = utils
|
||||||
|
}
|
||||||
|
|
||||||
|
void unstashPiperBin() {
|
||||||
|
|
||||||
|
if (utils.unstash('piper-bin').size() > 0) return
|
||||||
|
|
||||||
|
def libraries = getLibrariesInfo()
|
||||||
|
String version
|
||||||
|
libraries.each {lib ->
|
||||||
|
if (lib.name == 'piper-lib-os') {
|
||||||
|
version = lib.version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def fallbackUrl = 'https://github.com/SAP/jenkins-library/releases/latest/download/piper_master'
|
||||||
|
def piperBinUrl = (version == 'master') ? fallbackUrl : "https://github.com/SAP/jenkins-library/releases/tag/${version}"
|
||||||
|
|
||||||
|
boolean downloaded = downloadGoBinary(piperBinUrl)
|
||||||
|
if (!downloaded) {
|
||||||
|
//Inform that no Piper binary is available for used library branch
|
||||||
|
steps.echo ("Not able to download go binary of Piper for version ${version}")
|
||||||
|
//Fallback to master version & throw error in case this fails
|
||||||
|
steps.retry(5) {
|
||||||
|
if (!downloadGoBinary(fallbackUrl)) {
|
||||||
|
steps.sleep(2)
|
||||||
|
steps.error("Download of Piper go binary failed.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
utils.stashWithMessage('piper-bin', 'failed to stash piper binary', 'piper')
|
||||||
|
}
|
||||||
|
|
||||||
|
List getLibrariesInfo() {
|
||||||
|
return new JenkinsUtils().getLibrariesInfo()
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean downloadGoBinary(url) {
|
||||||
|
|
||||||
|
def httpStatus = steps.sh(returnStdout: true, script: "curl --insecure --silent --location --write-out '%{http_code}' --output ./piper '${url}'")
|
||||||
|
|
||||||
|
if (httpStatus == '200') {
|
||||||
|
steps.sh(script: 'chmod +x ./piper')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
@ -71,6 +71,16 @@ class JenkinsUtilsTest extends BasePiperTest {
|
|||||||
return triggerCause
|
return triggerCause
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
def getAction(type) {
|
||||||
|
return new Object() {
|
||||||
|
def getLibraries() {
|
||||||
|
return [
|
||||||
|
[name: 'lib1', version: '1', trusted: true],
|
||||||
|
[name: 'lib2', version: '2', trusted: false],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
LibraryLoadingTestExecutionListener.prepareObjectInterceptors(rawBuildMock)
|
LibraryLoadingTestExecutionListener.prepareObjectInterceptors(rawBuildMock)
|
||||||
@ -130,4 +140,12 @@ class JenkinsUtilsTest extends BasePiperTest {
|
|||||||
userId = null
|
userId = null
|
||||||
assertThat(jenkinsUtils.getJobStartedByUserId(), isEmptyOrNullString())
|
assertThat(jenkinsUtils.getJobStartedByUserId(), isEmptyOrNullString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetLibrariesInfo() {
|
||||||
|
def libs
|
||||||
|
libs = jenkinsUtils.getLibrariesInfo()
|
||||||
|
assertThat(libs[0], is([name: 'lib1', version: '1', trusted: true]))
|
||||||
|
assertThat(libs[1], is([name: 'lib2', version: '2', trusted: false]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
129
test/groovy/com/sap/piper/PiperGoUtilsTest.groovy
Normal file
129
test/groovy/com/sap/piper/PiperGoUtilsTest.groovy
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
package com.sap.piper
|
||||||
|
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.rules.ExpectedException
|
||||||
|
import org.junit.rules.RuleChain
|
||||||
|
import util.BasePiperTest
|
||||||
|
import util.JenkinsLoggingRule
|
||||||
|
import util.JenkinsShellCallRule
|
||||||
|
import util.Rules
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsString
|
||||||
|
import static org.hamcrest.Matchers.is
|
||||||
|
import static org.junit.Assert.assertThat
|
||||||
|
|
||||||
|
class PiperGoUtilsTest extends BasePiperTest {
|
||||||
|
|
||||||
|
public ExpectedException exception = ExpectedException.none()
|
||||||
|
public JenkinsShellCallRule shellCallRule = new JenkinsShellCallRule(this)
|
||||||
|
public JenkinsLoggingRule loggingRule = new JenkinsLoggingRule(this)
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public RuleChain ruleChain = Rules.getCommonRules(this)
|
||||||
|
.around(shellCallRule)
|
||||||
|
.around(exception)
|
||||||
|
.around(loggingRule)
|
||||||
|
|
||||||
|
@Before
|
||||||
|
void init() {
|
||||||
|
helper.registerAllowedMethod("retry", [Integer, Closure], null)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUnstashPiperBinAvailable() {
|
||||||
|
|
||||||
|
def piperBinStash = 'piper-bin'
|
||||||
|
|
||||||
|
// this mocks utils.unstash
|
||||||
|
helper.registerAllowedMethod("unstash", [String.class], { stashFileName ->
|
||||||
|
if (stashFileName != piperBinStash) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [piperBinStash]
|
||||||
|
})
|
||||||
|
|
||||||
|
def piperGoUtils = new PiperGoUtils(nullScript, utils)
|
||||||
|
|
||||||
|
piperGoUtils.unstashPiperBin()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUnstashPiperBinMaster() {
|
||||||
|
|
||||||
|
def piperGoUtils = new PiperGoUtils(nullScript, utils)
|
||||||
|
piperGoUtils.metaClass.getLibrariesInfo = {-> return [[name: 'piper-lib-os', version: 'master']]}
|
||||||
|
|
||||||
|
// this mocks utils.unstash - mimic stash not existing
|
||||||
|
helper.registerAllowedMethod("unstash", [String.class], { stashFileName ->
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
|
||||||
|
shellCallRule.setReturnValue('curl --insecure --silent --location --write-out \'%{http_code}\' --output ./piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper_master\'', '200')
|
||||||
|
|
||||||
|
piperGoUtils.unstashPiperBin()
|
||||||
|
assertThat(shellCallRule.shell.size(), is(2))
|
||||||
|
assertThat(shellCallRule.shell[0].toString(), is('curl --insecure --silent --location --write-out \'%{http_code}\' --output ./piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper_master\''))
|
||||||
|
assertThat(shellCallRule.shell[1].toString(), is('chmod +x ./piper'))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUnstashPiperBinNonMaster() {
|
||||||
|
|
||||||
|
def piperGoUtils = new PiperGoUtils(nullScript, utils)
|
||||||
|
piperGoUtils.metaClass.getLibrariesInfo = {-> return [[name: 'piper-lib-os', version: 'testTag']]}
|
||||||
|
|
||||||
|
// this mocks utils.unstash - mimic stash not existing
|
||||||
|
helper.registerAllowedMethod("unstash", [String.class], { stashFileName ->
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
|
||||||
|
shellCallRule.setReturnValue('curl --insecure --silent --location --write-out \'%{http_code}\' --output ./piper \'https://github.com/SAP/jenkins-library/releases/tag/testTag\'', '200')
|
||||||
|
|
||||||
|
piperGoUtils.unstashPiperBin()
|
||||||
|
assertThat(shellCallRule.shell.size(), is(2))
|
||||||
|
assertThat(shellCallRule.shell[0].toString(), is('curl --insecure --silent --location --write-out \'%{http_code}\' --output ./piper \'https://github.com/SAP/jenkins-library/releases/tag/testTag\''))
|
||||||
|
assertThat(shellCallRule.shell[1].toString(), is('chmod +x ./piper'))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testUnstashPiperBinFallback() {
|
||||||
|
|
||||||
|
def piperGoUtils = new PiperGoUtils(nullScript, utils)
|
||||||
|
piperGoUtils.metaClass.getLibrariesInfo = {-> return [[name: 'piper-lib-os', version: 'notAvailable']]}
|
||||||
|
|
||||||
|
shellCallRule.setReturnValue('curl --insecure --silent --location --write-out \'%{http_code}\' --output ./piper \'https://github.com/SAP/jenkins-library/releases/tag/notAvailable\'', '404')
|
||||||
|
shellCallRule.setReturnValue('curl --insecure --silent --location --write-out \'%{http_code}\' --output ./piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper_master\'', '200')
|
||||||
|
|
||||||
|
// this mocks utils.unstash - mimic stash not existing
|
||||||
|
helper.registerAllowedMethod("unstash", [String.class], { stashFileName ->
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
|
||||||
|
piperGoUtils.unstashPiperBin()
|
||||||
|
assertThat(shellCallRule.shell.size(), is(3))
|
||||||
|
assertThat(shellCallRule.shell[0].toString(), is('curl --insecure --silent --location --write-out \'%{http_code}\' --output ./piper \'https://github.com/SAP/jenkins-library/releases/tag/notAvailable\''))
|
||||||
|
assertThat(shellCallRule.shell[1].toString(), is('curl --insecure --silent --location --write-out \'%{http_code}\' --output ./piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper_master\''))
|
||||||
|
assertThat(shellCallRule.shell[2].toString(), is('chmod +x ./piper'))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testDownloadFailed() {
|
||||||
|
def piperGoUtils = new PiperGoUtils(nullScript, utils)
|
||||||
|
piperGoUtils.metaClass.getLibrariesInfo = {-> return [[name: 'piper-lib-os', version: 'notAvailable']]}
|
||||||
|
|
||||||
|
shellCallRule.setReturnValue('curl --insecure --silent --location --write-out \'%{http_code}\' --output ./piper \'https://github.com/SAP/jenkins-library/releases/tag/notAvailable\'', '404')
|
||||||
|
shellCallRule.setReturnValue('curl --insecure --silent --location --write-out \'%{http_code}\' --output ./piper \'https://github.com/SAP/jenkins-library/releases/latest/download/piper_master\'', '500')
|
||||||
|
|
||||||
|
helper.registerAllowedMethod("unstash", [String.class], { stashFileName ->
|
||||||
|
return []
|
||||||
|
})
|
||||||
|
|
||||||
|
exception.expectMessage(containsString('Download of Piper go binary failed'))
|
||||||
|
piperGoUtils.unstashPiperBin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user