You've already forked sap-jenkins-library
							
							
				mirror of
				https://github.com/SAP/jenkins-library.git
				synced 2025-10-30 23:57:50 +02:00 
			
		
		
		
	githubCreateIssue_fix (#4151)
* extend githubCreateIssue to handle long body Co-authored-by: Jordi van Liempt <35920075+jliempt@users.noreply.github.com>
This commit is contained in:
		| @@ -77,7 +77,8 @@ func (c *checkmarxExecuteScanUtilsBundle) Open(name string) (*os.File, error) { | ||||
| } | ||||
|  | ||||
| func (c *checkmarxExecuteScanUtilsBundle) CreateIssue(ghCreateIssueOptions *piperGithub.CreateIssueOptions) error { | ||||
| 	return piperGithub.CreateIssue(ghCreateIssueOptions) | ||||
| 	_, err := piperGithub.CreateIssue(ghCreateIssueOptions) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (c *checkmarxExecuteScanUtilsBundle) GetIssueService() *github.IssuesService { | ||||
|   | ||||
| @@ -78,7 +78,8 @@ func (f *fortifyUtilsBundle) GetArtifact(buildTool, buildDescriptorFile string, | ||||
| } | ||||
|  | ||||
| func (f *fortifyUtilsBundle) CreateIssue(ghCreateIssueOptions *piperGithub.CreateIssueOptions) error { | ||||
| 	return piperGithub.CreateIssue(ghCreateIssueOptions) | ||||
| 	_, err := piperGithub.CreateIssue(ghCreateIssueOptions) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (f *fortifyUtilsBundle) GetIssueService() *github.IssuesService { | ||||
|   | ||||
| @@ -2,34 +2,71 @@ package cmd | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/SAP/jenkins-library/pkg/piperutils" | ||||
| 	"github.com/SAP/jenkins-library/pkg/telemetry" | ||||
| 	"github.com/pkg/errors" | ||||
|  | ||||
| 	piperGithub "github.com/SAP/jenkins-library/pkg/github" | ||||
| 	github "github.com/google/go-github/v45/github" | ||||
| ) | ||||
|  | ||||
| type githubCreateIssueUtils interface { | ||||
| 	FileRead(string) ([]byte, error) | ||||
| } | ||||
|  | ||||
| func githubCreateIssue(config githubCreateIssueOptions, telemetryData *telemetry.CustomData) { | ||||
| 	err := runGithubCreateIssue(&config, telemetryData) | ||||
| 	fileUtils := &piperutils.Files{} | ||||
| 	options := piperGithub.CreateIssueOptions{} | ||||
| 	err := runGithubCreateIssue(&config, telemetryData, &options, fileUtils, piperGithub.CreateIssue) | ||||
| 	if err != nil { | ||||
| 		log.Entry().WithError(err).Fatal("Failed to comment on issue") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func runGithubCreateIssue(config *githubCreateIssueOptions, _ *telemetry.CustomData) error { | ||||
|  | ||||
| 	options := piperGithub.CreateIssueOptions{} | ||||
| 	err := transformConfig(config, &options, ioutil.ReadFile) | ||||
| func runGithubCreateIssue(config *githubCreateIssueOptions, _ *telemetry.CustomData, options *piperGithub.CreateIssueOptions, utils githubCreateIssueUtils, createIssue func(*piperGithub.CreateIssueOptions) (*github.Issue, error)) error { | ||||
| 	chunks, err := getBody(config, utils.FileRead) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return piperGithub.CreateIssue(&options) | ||||
| 	transformConfig(config, options, chunks[0]) | ||||
| 	issue, err := createIssue(options) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if len(chunks) > 1 { | ||||
| 		for _, v := range chunks[1:] { | ||||
| 			options.Body = []byte(v) | ||||
| 			options.Issue = issue | ||||
| 			options.UpdateExisting = true | ||||
| 			_, err = createIssue(options) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func transformConfig(config *githubCreateIssueOptions, options *piperGithub.CreateIssueOptions, readFile func(string) ([]byte, error)) error { | ||||
| func getBody(config *githubCreateIssueOptions, readFile func(string) ([]byte, error)) ([]string, error) { | ||||
| 	var bodyString []rune | ||||
| 	if len(config.Body)+len(config.BodyFilePath) == 0 { | ||||
| 		return nil, fmt.Errorf("either parameter `body` or parameter `bodyFilePath` is required") | ||||
| 	} | ||||
| 	if len(config.Body) == 0 { | ||||
| 		issueContent, err := readFile(config.BodyFilePath) | ||||
| 		if err != nil { | ||||
| 			return nil, errors.Wrapf(err, "failed to read file '%v'", config.BodyFilePath) | ||||
| 		} | ||||
| 		bodyString = []rune(string(issueContent)) | ||||
| 	} else { | ||||
| 		bodyString = []rune(config.Body) | ||||
| 	} | ||||
| 	return getChunks(bodyString, config.ChunkSize), nil | ||||
| } | ||||
|  | ||||
| func transformConfig(config *githubCreateIssueOptions, options *piperGithub.CreateIssueOptions, body string) { | ||||
| 	options.Token = config.Token | ||||
| 	options.APIURL = config.APIURL | ||||
| 	options.Owner = config.Owner | ||||
| @@ -38,16 +75,21 @@ func transformConfig(config *githubCreateIssueOptions, options *piperGithub.Crea | ||||
| 	options.Body = []byte(config.Body) | ||||
| 	options.Assignees = config.Assignees | ||||
| 	options.UpdateExisting = config.UpdateExisting | ||||
|  | ||||
| 	if len(config.Body)+len(config.BodyFilePath) == 0 { | ||||
| 		return fmt.Errorf("either parameter `body` or parameter `bodyFilePath` is required") | ||||
| 	} | ||||
| 	if len(config.Body) == 0 { | ||||
| 		issueContent, err := readFile(config.BodyFilePath) | ||||
| 		if err != nil { | ||||
| 			return errors.Wrapf(err, "failed to read file '%v'", config.BodyFilePath) | ||||
| 		} | ||||
| 		options.Body = issueContent | ||||
| 	} | ||||
| 	return nil | ||||
| 	options.Body = []byte(body) | ||||
| } | ||||
|  | ||||
| func getChunks(value []rune, chunkSize int) []string { | ||||
| 	chunks := []string{} | ||||
| 	length := len(value) | ||||
| 	if length == 0 { | ||||
| 		return []string{""} | ||||
| 	} | ||||
| 	for i := 0; i < length; i += chunkSize { | ||||
| 		to := length | ||||
| 		if to > i+chunkSize { | ||||
| 			to = i + chunkSize | ||||
| 		} | ||||
| 		chunks = append(chunks, string(value[i:to])) | ||||
| 	} | ||||
| 	return chunks | ||||
| } | ||||
|   | ||||
| @@ -18,6 +18,7 @@ import ( | ||||
| type githubCreateIssueOptions struct { | ||||
| 	APIURL         string   `json:"apiUrl,omitempty"` | ||||
| 	Assignees      []string `json:"assignees,omitempty"` | ||||
| 	ChunkSize      int      `json:"chunkSize,omitempty"` | ||||
| 	Body           string   `json:"body,omitempty"` | ||||
| 	BodyFilePath   string   `json:"bodyFilePath,omitempty"` | ||||
| 	Owner          string   `json:"owner,omitempty"` | ||||
| @@ -125,6 +126,7 @@ You will be able to use this step for example for regular jobs to report into yo | ||||
| func addGithubCreateIssueFlags(cmd *cobra.Command, stepConfig *githubCreateIssueOptions) { | ||||
| 	cmd.Flags().StringVar(&stepConfig.APIURL, "apiUrl", `https://api.github.com`, "Set the GitHub API url.") | ||||
| 	cmd.Flags().StringSliceVar(&stepConfig.Assignees, "assignees", []string{``}, "Defines the assignees for the Issue.") | ||||
| 	cmd.Flags().IntVar(&stepConfig.ChunkSize, "chunkSize", 65500, "Defines size of the chunk. If content exceed chunk size it'll be sliced into chunks and stored in comments") | ||||
| 	cmd.Flags().StringVar(&stepConfig.Body, "body", os.Getenv("PIPER_body"), "Defines the content of the issue, e.g. using markdown syntax.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.BodyFilePath, "bodyFilePath", os.Getenv("PIPER_bodyFilePath"), "Defines the path to a file containing the markdown content for the issue. This can be used instead of [`body`](#body)") | ||||
| 	cmd.Flags().StringVar(&stepConfig.Owner, "owner", os.Getenv("PIPER_owner"), "Name of the GitHub organization.") | ||||
| @@ -172,6 +174,15 @@ func githubCreateIssueMetadata() config.StepData { | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     []string{``}, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "chunkSize", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "int", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     65500, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "body", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
|   | ||||
| @@ -3,13 +3,57 @@ package cmd | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/mock" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | ||||
| 	piperGithub "github.com/SAP/jenkins-library/pkg/github" | ||||
| 	"github.com/SAP/jenkins-library/pkg/mock" | ||||
| 	github "github.com/google/go-github/v45/github" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestGetChunk(t *testing.T) { | ||||
| 	tests := []struct { | ||||
| 		name           string | ||||
| 		chunkSize      int | ||||
| 		largeString    string | ||||
| 		expectedChunks []string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "large string", | ||||
| 			largeString: `The quick | ||||
| brown fox jumps | ||||
| over | ||||
| the lazy dog | ||||
| `, | ||||
| 			chunkSize:      12, | ||||
| 			expectedChunks: []string{"The quick\nbr", "own fox jump", "s\nover\nthe l", "azy dog\n"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:           "small string", | ||||
| 			largeString:    `small`, | ||||
| 			chunkSize:      12, | ||||
| 			expectedChunks: []string{"small"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:           "exact size", | ||||
| 			largeString:    `exact size12`, | ||||
| 			chunkSize:      12, | ||||
| 			expectedChunks: []string{"exact size12"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			name:           "empty string", | ||||
| 			largeString:    ``, | ||||
| 			chunkSize:      12, | ||||
| 			expectedChunks: []string{""}, | ||||
| 		}, | ||||
| 	} | ||||
| 	for _, test := range tests { | ||||
| 		test := test | ||||
| 		t.Run(test.name, func(t *testing.T) { | ||||
| 			chunks := getChunks([]rune(test.largeString), test.chunkSize) | ||||
| 			assert.ElementsMatch(t, test.expectedChunks, chunks) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestTransformConfig(t *testing.T) { | ||||
| 	t.Parallel() | ||||
|  | ||||
| @@ -22,11 +66,17 @@ func TestTransformConfig(t *testing.T) { | ||||
| 			Body:       "This is my test body", | ||||
| 			Title:      "This is my title", | ||||
| 			Assignees:  []string{"userIdOne", "userIdTwo"}, | ||||
| 			ChunkSize:  100, | ||||
| 		} | ||||
| 		options := piperGithub.CreateIssueOptions{} | ||||
| 		resultChunks := []string{} | ||||
| 		createIssue := func(options *piperGithub.CreateIssueOptions) (*github.Issue, error) { | ||||
| 			resultChunks = append(resultChunks, string(options.Body)) | ||||
| 			return nil, nil | ||||
| 		} | ||||
|  | ||||
| 		// test | ||||
| 		err := transformConfig(&config, &options, filesMock.FileRead) | ||||
| 		err := runGithubCreateIssue(&config, nil, &options, &filesMock, createIssue) | ||||
|  | ||||
| 		// assert | ||||
| 		assert.NoError(t, err) | ||||
| @@ -34,10 +84,10 @@ func TestTransformConfig(t *testing.T) { | ||||
| 		assert.Equal(t, config.APIURL, options.APIURL) | ||||
| 		assert.Equal(t, config.Owner, options.Owner) | ||||
| 		assert.Equal(t, config.Repository, options.Repository) | ||||
| 		assert.Equal(t, []byte(config.Body), options.Body) | ||||
| 		assert.Equal(t, config.Title, options.Title) | ||||
| 		assert.Equal(t, config.Assignees, options.Assignees) | ||||
| 		assert.Equal(t, config.UpdateExisting, options.UpdateExisting) | ||||
| 		assert.ElementsMatch(t, resultChunks, []string{string(config.Body)}) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Success bodyFilePath", func(t *testing.T) { | ||||
| @@ -50,11 +100,16 @@ func TestTransformConfig(t *testing.T) { | ||||
| 			BodyFilePath: "test.md", | ||||
| 			Title:        "This is my title", | ||||
| 			Assignees:    []string{"userIdOne", "userIdTwo"}, | ||||
| 			ChunkSize:    100, | ||||
| 		} | ||||
| 		options := piperGithub.CreateIssueOptions{} | ||||
|  | ||||
| 		resultChunks := []string{} | ||||
| 		createIssue := func(options *piperGithub.CreateIssueOptions) (*github.Issue, error) { | ||||
| 			resultChunks = append(resultChunks, string(options.Body)) | ||||
| 			return nil, nil | ||||
| 		} | ||||
| 		// test | ||||
| 		err := transformConfig(&config, &options, filesMock.FileRead) | ||||
| 		err := runGithubCreateIssue(&config, nil, &options, &filesMock, createIssue) | ||||
|  | ||||
| 		// assert | ||||
| 		assert.NoError(t, err) | ||||
| @@ -62,20 +117,24 @@ func TestTransformConfig(t *testing.T) { | ||||
| 		assert.Equal(t, config.APIURL, options.APIURL) | ||||
| 		assert.Equal(t, config.Owner, options.Owner) | ||||
| 		assert.Equal(t, config.Repository, options.Repository) | ||||
| 		assert.Equal(t, []byte("Test markdown"), options.Body) | ||||
| 		assert.Equal(t, config.Title, options.Title) | ||||
| 		assert.Equal(t, config.Assignees, options.Assignees) | ||||
| 		assert.Equal(t, config.UpdateExisting, options.UpdateExisting) | ||||
| 		assert.ElementsMatch(t, resultChunks, []string{"Test markdown"}) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Error - missing issue body", func(t *testing.T) { | ||||
| 		// init | ||||
| 		filesMock := mock.FilesMock{} | ||||
| 		config := githubCreateIssueOptions{} | ||||
| 		config := githubCreateIssueOptions{ChunkSize: 100} | ||||
| 		options := piperGithub.CreateIssueOptions{} | ||||
|  | ||||
| 		resultChunks := []string{} | ||||
| 		createIssue := func(options *piperGithub.CreateIssueOptions) (*github.Issue, error) { | ||||
| 			resultChunks = append(resultChunks, string(options.Body)) | ||||
| 			return nil, nil | ||||
| 		} | ||||
| 		// test | ||||
| 		err := transformConfig(&config, &options, filesMock.FileRead) | ||||
| 		err := runGithubCreateIssue(&config, nil, &options, &filesMock, createIssue) | ||||
|  | ||||
| 		// assert | ||||
| 		assert.EqualError(t, err, "either parameter `body` or parameter `bodyFilePath` is required") | ||||
|   | ||||
| @@ -27,15 +27,16 @@ type githubCreateCommentService interface { | ||||
|  | ||||
| // CreateIssueOptions to configure the creation | ||||
| type CreateIssueOptions struct { | ||||
| 	APIURL         string   `json:"apiUrl,omitempty"` | ||||
| 	Assignees      []string `json:"assignees,omitempty"` | ||||
| 	Body           []byte   `json:"body,omitempty"` | ||||
| 	Owner          string   `json:"owner,omitempty"` | ||||
| 	Repository     string   `json:"repository,omitempty"` | ||||
| 	Title          string   `json:"title,omitempty"` | ||||
| 	UpdateExisting bool     `json:"updateExisting,omitempty"` | ||||
| 	Token          string   `json:"token,omitempty"` | ||||
| 	TrustedCerts   []string `json:"trustedCerts,omitempty"` | ||||
| 	APIURL         string        `json:"apiUrl,omitempty"` | ||||
| 	Assignees      []string      `json:"assignees,omitempty"` | ||||
| 	Body           []byte        `json:"body,omitempty"` | ||||
| 	Owner          string        `json:"owner,omitempty"` | ||||
| 	Repository     string        `json:"repository,omitempty"` | ||||
| 	Title          string        `json:"title,omitempty"` | ||||
| 	UpdateExisting bool          `json:"updateExisting,omitempty"` | ||||
| 	Token          string        `json:"token,omitempty"` | ||||
| 	TrustedCerts   []string      `json:"trustedCerts,omitempty"` | ||||
| 	Issue          *github.Issue `json:"issue,omitempty"` | ||||
| } | ||||
|  | ||||
| // NewClient creates a new GitHub client using an OAuth token for authentication | ||||
| @@ -74,15 +75,15 @@ func NewClient(token, apiURL, uploadURL string, trustedCerts []string) (context. | ||||
| 	return ctx, client, nil | ||||
| } | ||||
|  | ||||
| func CreateIssue(ghCreateIssueOptions *CreateIssueOptions) error { | ||||
| func CreateIssue(ghCreateIssueOptions *CreateIssueOptions) (*github.Issue, error) { | ||||
| 	ctx, client, err := NewClient(ghCreateIssueOptions.Token, ghCreateIssueOptions.APIURL, "", ghCreateIssueOptions.TrustedCerts) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "failed to get GitHub client") | ||||
| 		return nil, errors.Wrap(err, "failed to get GitHub client") | ||||
| 	} | ||||
| 	return createIssueLocal(ctx, ghCreateIssueOptions, client.Issues, client.Search, client.Issues) | ||||
| } | ||||
|  | ||||
| func createIssueLocal(ctx context.Context, ghCreateIssueOptions *CreateIssueOptions, ghCreateIssueService githubCreateIssueService, ghSearchIssuesService githubSearchIssuesService, ghCreateCommentService githubCreateCommentService) error { | ||||
| func createIssueLocal(ctx context.Context, ghCreateIssueOptions *CreateIssueOptions, ghCreateIssueService githubCreateIssueService, ghSearchIssuesService githubSearchIssuesService, ghCreateCommentService githubCreateCommentService) (*github.Issue, error) { | ||||
| 	issue := github.IssueRequest{ | ||||
| 		Title: &ghCreateIssueOptions.Title, | ||||
| 	} | ||||
| @@ -102,17 +103,20 @@ func createIssueLocal(ctx context.Context, ghCreateIssueOptions *CreateIssueOpti | ||||
| 	var existingIssue *github.Issue = nil | ||||
|  | ||||
| 	if ghCreateIssueOptions.UpdateExisting { | ||||
| 		queryString := fmt.Sprintf("is:open is:issue repo:%v/%v in:title %v", ghCreateIssueOptions.Owner, ghCreateIssueOptions.Repository, ghCreateIssueOptions.Title) | ||||
| 		searchResult, resp, err := ghSearchIssuesService.Issues(ctx, queryString, nil) | ||||
| 		if err != nil { | ||||
| 			if resp != nil { | ||||
| 				log.Entry().Errorf("GitHub search issue returned response code %v", resp.Status) | ||||
| 			} | ||||
| 			return errors.Wrap(err, "error occurred when looking for existing issue") | ||||
| 		} else { | ||||
| 			for _, value := range searchResult.Issues { | ||||
| 				if value != nil && *value.Title == ghCreateIssueOptions.Title { | ||||
| 					existingIssue = value | ||||
| 		existingIssue = ghCreateIssueOptions.Issue | ||||
| 		if existingIssue == nil { | ||||
| 			queryString := fmt.Sprintf("is:open is:issue repo:%v/%v in:title %v", ghCreateIssueOptions.Owner, ghCreateIssueOptions.Repository, ghCreateIssueOptions.Title) | ||||
| 			searchResult, resp, err := ghSearchIssuesService.Issues(ctx, queryString, nil) | ||||
| 			if err != nil { | ||||
| 				if resp != nil { | ||||
| 					log.Entry().Errorf("GitHub search issue returned response code %v", resp.Status) | ||||
| 				} | ||||
| 				return nil, errors.Wrap(err, "error occurred when looking for existing issue") | ||||
| 			} else { | ||||
| 				for _, value := range searchResult.Issues { | ||||
| 					if value != nil && *value.Title == ghCreateIssueOptions.Title { | ||||
| 						existingIssue = value | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| @@ -124,7 +128,7 @@ func createIssueLocal(ctx context.Context, ghCreateIssueOptions *CreateIssueOpti | ||||
| 				if resp != nil { | ||||
| 					log.Entry().Errorf("GitHub create comment returned response code %v", resp.Status) | ||||
| 				} | ||||
| 				return errors.Wrap(err, "error occurred when adding comment to existing issue") | ||||
| 				return nil, errors.Wrap(err, "error occurred when adding comment to existing issue") | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -135,10 +139,11 @@ func createIssueLocal(ctx context.Context, ghCreateIssueOptions *CreateIssueOpti | ||||
| 			if resp != nil { | ||||
| 				log.Entry().Errorf("GitHub create issue returned response code %v", resp.Status) | ||||
| 			} | ||||
| 			return errors.Wrap(err, "error occurred when creating issue") | ||||
| 			return nil, errors.Wrap(err, "error occurred when creating issue") | ||||
| 		} | ||||
| 		log.Entry().Debugf("New issue created: %v", newIssue) | ||||
| 		existingIssue = newIssue | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| 	return existingIssue, nil | ||||
| } | ||||
|   | ||||
| @@ -80,11 +80,13 @@ func (g *ghSearchIssuesMock) Issues(ctx context.Context, query string, opts *git | ||||
|  | ||||
| type ghCreateCommentMock struct { | ||||
| 	issueComment      *github.IssueComment | ||||
| 	issueNumber       int | ||||
| 	issueCommentError error | ||||
| } | ||||
|  | ||||
| func (g *ghCreateCommentMock) CreateComment(ctx context.Context, owner string, repo string, number int, comment *github.IssueComment) (*github.IssueComment, *github.Response, error) { | ||||
| 	g.issueComment = comment | ||||
| 	g.issueNumber = number | ||||
| 	ghRes := github.Response{Response: &http.Response{Status: "200"}} | ||||
| 	if g.issueCommentError != nil { | ||||
| 		ghRes.Status = "401" | ||||
| @@ -114,7 +116,7 @@ func TestRunGithubCreateIssue(t *testing.T) { | ||||
| 		} | ||||
|  | ||||
| 		// test | ||||
| 		err := createIssueLocal(ctx, &config, &ghCreateIssueService, &ghSearchIssuesMock, &ghCreateCommentMock) | ||||
| 		_, err := createIssueLocal(ctx, &config, &ghCreateIssueService, &ghSearchIssuesMock, &ghCreateCommentMock) | ||||
|  | ||||
| 		// assert | ||||
| 		assert.NoError(t, err) | ||||
| @@ -143,7 +145,7 @@ func TestRunGithubCreateIssue(t *testing.T) { | ||||
| 		} | ||||
|  | ||||
| 		// test | ||||
| 		err := createIssueLocal(ctx, &config, nil, &ghSearchIssuesMock, &ghCreateCommentMock) | ||||
| 		_, err := createIssueLocal(ctx, &config, nil, &ghSearchIssuesMock, &ghCreateCommentMock) | ||||
|  | ||||
| 		// assert | ||||
| 		assert.NoError(t, err) | ||||
| @@ -154,6 +156,38 @@ func TestRunGithubCreateIssue(t *testing.T) { | ||||
| 		assert.Equal(t, "This is my test body", ghCreateCommentMock.issueComment.GetBody()) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Success update existing based on instance", func(t *testing.T) { | ||||
| 		// init | ||||
| 		ghSearchIssuesMock := ghSearchIssuesMock{ | ||||
| 			issueID: 1, | ||||
| 		} | ||||
| 		ghCreateCommentMock := ghCreateCommentMock{} | ||||
| 		var id int64 = 2 | ||||
| 		var number int = 123 | ||||
| 		config := CreateIssueOptions{ | ||||
| 			Owner:          "TEST", | ||||
| 			Repository:     "test", | ||||
| 			Body:           []byte("This is my test body"), | ||||
| 			Title:          "This is my title", | ||||
| 			Assignees:      []string{"userIdOne", "userIdTwo"}, | ||||
| 			UpdateExisting: true, | ||||
| 			Issue: &github.Issue{ | ||||
| 				ID:     &id, | ||||
| 				Number: &number, | ||||
| 			}, | ||||
| 		} | ||||
|  | ||||
| 		// test | ||||
| 		_, err := createIssueLocal(ctx, &config, nil, &ghSearchIssuesMock, &ghCreateCommentMock) | ||||
|  | ||||
| 		// assert | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Nil(t, ghSearchIssuesMock.issuesSearchResult) | ||||
| 		assert.NotNil(t, ghCreateCommentMock.issueComment) | ||||
| 		assert.Equal(t, ghCreateCommentMock.issueNumber, number) | ||||
| 		assert.Equal(t, "This is my test body", ghCreateCommentMock.issueComment.GetBody()) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Empty body", func(t *testing.T) { | ||||
| 		// init | ||||
| 		ghCreateIssueService := ghCreateIssueMock{ | ||||
| @@ -173,7 +207,7 @@ func TestRunGithubCreateIssue(t *testing.T) { | ||||
| 		} | ||||
|  | ||||
| 		// test | ||||
| 		err := createIssueLocal(ctx, &config, &ghCreateIssueService, &ghSearchIssuesMock, &ghCreateCommentMock) | ||||
| 		_, err := createIssueLocal(ctx, &config, &ghCreateIssueService, &ghSearchIssuesMock, &ghCreateCommentMock) | ||||
|  | ||||
| 		// assert | ||||
| 		assert.NoError(t, err) | ||||
| @@ -194,7 +228,7 @@ func TestRunGithubCreateIssue(t *testing.T) { | ||||
| 		} | ||||
|  | ||||
| 		// test | ||||
| 		err := createIssueLocal(ctx, &config, &ghCreateIssueService, nil, nil) | ||||
| 		_, err := createIssueLocal(ctx, &config, &ghCreateIssueService, nil, nil) | ||||
|  | ||||
| 		// assert | ||||
| 		assert.EqualError(t, err, "error occurred when creating issue: error creating issue") | ||||
|   | ||||
| @@ -33,6 +33,14 @@ spec: | ||||
|         type: "[]string" | ||||
|         default: [] | ||||
|         mandatory: false | ||||
|       - name: chunkSize | ||||
|         description: Defines size of the chunk. If content exceed chunk size it'll be sliced into chunks and stored in comments | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         type: int | ||||
|         default: 65500 | ||||
|       - name: body | ||||
|         description: Defines the content of the issue, e.g. using markdown syntax. | ||||
|         scope: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user