mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-04-15 11:56:45 +02:00
add step to create a GitHub comment (#2479)
* add step to create a GitHub comment * add docs * mandatory parameters * add command * Update githubCommentIssue.go * add groovy library step Co-authored-by: Sven Merk <33895725+nevskrem@users.noreply.github.com>
This commit is contained in:
parent
cb069148d2
commit
cf7ca8f791
42
cmd/githubCommentIssue.go
Normal file
42
cmd/githubCommentIssue.go
Normal file
@ -0,0 +1,42 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"github.com/google/go-github/v32/github"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
piperGithub "github.com/SAP/jenkins-library/pkg/github"
|
||||
)
|
||||
|
||||
type githubIssueCommentService interface {
|
||||
CreateComment(ctx context.Context, owner string, repo string, number int, comment *github.IssueComment) (*github.IssueComment, *github.Response, error)
|
||||
}
|
||||
|
||||
func githubCommentIssue(config githubCommentIssueOptions, telemetryData *telemetry.CustomData) {
|
||||
ctx, client, err := piperGithub.NewClient(config.Token, config.APIURL, "")
|
||||
if err != nil {
|
||||
log.Entry().WithError(err).Fatal("Failed to get GitHub client")
|
||||
}
|
||||
err = runGithubCommentIssue(ctx, &config, telemetryData, client.Issues)
|
||||
if err != nil {
|
||||
log.Entry().WithError(err).Fatal("Failed to comment on issue")
|
||||
}
|
||||
}
|
||||
|
||||
func runGithubCommentIssue(ctx context.Context, config *githubCommentIssueOptions, _ *telemetry.CustomData, ghIssueCommentService githubIssueCommentService) error {
|
||||
issueComment := github.IssueComment{
|
||||
Body: &config.Body,
|
||||
}
|
||||
|
||||
newcomment, resp, err := ghIssueCommentService.CreateComment(ctx, config.Owner, config.Repository, config.Number, &issueComment)
|
||||
if err != nil {
|
||||
log.Entry().Errorf("GitHub response code %v", resp.Status)
|
||||
return errors.Wrapf(err, "Error occurred when creating comment on issue %v", config.Number)
|
||||
}
|
||||
log.Entry().Debugf("New issue comment created for issue %v: %v", config.Number, newcomment)
|
||||
|
||||
return nil
|
||||
}
|
186
cmd/githubCommentIssue_generated.go
Normal file
186
cmd/githubCommentIssue_generated.go
Normal file
@ -0,0 +1,186 @@
|
||||
// Code generated by piper's step-generator. DO NOT EDIT.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/config"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type githubCommentIssueOptions struct {
|
||||
APIURL string `json:"apiUrl,omitempty"`
|
||||
Body string `json:"body,omitempty"`
|
||||
Number int `json:"number,omitempty"`
|
||||
Owner string `json:"owner,omitempty"`
|
||||
Repository string `json:"repository,omitempty"`
|
||||
Token string `json:"token,omitempty"`
|
||||
}
|
||||
|
||||
// GithubCommentIssueCommand Comment on GitHub issues and pull requests.
|
||||
func GithubCommentIssueCommand() *cobra.Command {
|
||||
const STEP_NAME = "githubCommentIssue"
|
||||
|
||||
metadata := githubCommentIssueMetadata()
|
||||
var stepConfig githubCommentIssueOptions
|
||||
var startTime time.Time
|
||||
|
||||
var createGithubCommentIssueCmd = &cobra.Command{
|
||||
Use: STEP_NAME,
|
||||
Short: "Comment on GitHub issues and pull requests.",
|
||||
Long: `This step allows you to add comments to existing GitHub issues or pull requests.
|
||||
|
||||
Pull requests are considered similar to issues and thus adding a comment can be done to an existing pull request as well.
|
||||
This comes in very handy when you want to make developers aware of certain things during a PR voting process, for example.`,
|
||||
PreRunE: func(cmd *cobra.Command, _ []string) error {
|
||||
startTime = time.Now()
|
||||
log.SetStepName(STEP_NAME)
|
||||
log.SetVerbose(GeneralConfig.Verbose)
|
||||
|
||||
path, _ := os.Getwd()
|
||||
fatalHook := &log.FatalHook{CorrelationID: GeneralConfig.CorrelationID, Path: path}
|
||||
log.RegisterHook(fatalHook)
|
||||
|
||||
err := PrepareConfig(cmd, &metadata, STEP_NAME, &stepConfig, config.OpenPiperFile)
|
||||
if err != nil {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return err
|
||||
}
|
||||
log.RegisterSecret(stepConfig.Token)
|
||||
|
||||
if len(GeneralConfig.HookConfig.SentryConfig.Dsn) > 0 {
|
||||
sentryHook := log.NewSentryHook(GeneralConfig.HookConfig.SentryConfig.Dsn, GeneralConfig.CorrelationID)
|
||||
log.RegisterHook(&sentryHook)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
telemetryData := telemetry.CustomData{}
|
||||
telemetryData.ErrorCode = "1"
|
||||
handler := func() {
|
||||
config.RemoveVaultSecretFiles()
|
||||
telemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds())
|
||||
telemetryData.ErrorCategory = log.GetErrorCategory().String()
|
||||
telemetry.Send(&telemetryData)
|
||||
}
|
||||
log.DeferExitHandler(handler)
|
||||
defer handler()
|
||||
telemetry.Initialize(GeneralConfig.NoTelemetry, STEP_NAME)
|
||||
githubCommentIssue(stepConfig, &telemetryData)
|
||||
telemetryData.ErrorCode = "0"
|
||||
log.Entry().Info("SUCCESS")
|
||||
},
|
||||
}
|
||||
|
||||
addGithubCommentIssueFlags(createGithubCommentIssueCmd, &stepConfig)
|
||||
return createGithubCommentIssueCmd
|
||||
}
|
||||
|
||||
func addGithubCommentIssueFlags(cmd *cobra.Command, stepConfig *githubCommentIssueOptions) {
|
||||
cmd.Flags().StringVar(&stepConfig.APIURL, "apiUrl", `https://api.github.com`, "Set the GitHub API url.")
|
||||
cmd.Flags().StringVar(&stepConfig.Body, "body", os.Getenv("PIPER_body"), "Defines the content of the comment, e.g. using markdown syntax.")
|
||||
cmd.Flags().IntVar(&stepConfig.Number, "number", 0, "Defines the number of the GitHub issue/pull request.")
|
||||
cmd.Flags().StringVar(&stepConfig.Owner, "owner", os.Getenv("PIPER_owner"), "Name of the GitHub organization.")
|
||||
cmd.Flags().StringVar(&stepConfig.Repository, "repository", os.Getenv("PIPER_repository"), "Name of the GitHub repository.")
|
||||
cmd.Flags().StringVar(&stepConfig.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.MarkFlagRequired("apiUrl")
|
||||
cmd.MarkFlagRequired("body")
|
||||
cmd.MarkFlagRequired("number")
|
||||
cmd.MarkFlagRequired("owner")
|
||||
cmd.MarkFlagRequired("repository")
|
||||
cmd.MarkFlagRequired("token")
|
||||
}
|
||||
|
||||
// retrieve step metadata
|
||||
func githubCommentIssueMetadata() config.StepData {
|
||||
var theMetaData = config.StepData{
|
||||
Metadata: config.StepMetadata{
|
||||
Name: "githubCommentIssue",
|
||||
Aliases: []config.Alias{},
|
||||
Description: "Comment on GitHub issues and pull requests.",
|
||||
},
|
||||
Spec: config.StepSpec{
|
||||
Inputs: config.StepInputs{
|
||||
Parameters: []config.StepParameters{
|
||||
{
|
||||
Name: "apiUrl",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{{Name: "githubApiUrl"}},
|
||||
},
|
||||
{
|
||||
Name: "body",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
{
|
||||
Name: "number",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "int",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
{
|
||||
Name: "owner",
|
||||
ResourceRef: []config.ResourceReference{
|
||||
{
|
||||
Name: "commonPipelineEnvironment",
|
||||
Param: "github/owner",
|
||||
},
|
||||
},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{{Name: "githubOrg"}},
|
||||
},
|
||||
{
|
||||
Name: "repository",
|
||||
ResourceRef: []config.ResourceReference{
|
||||
{
|
||||
Name: "commonPipelineEnvironment",
|
||||
Param: "github/repository",
|
||||
},
|
||||
},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{{Name: "githubRepo"}},
|
||||
},
|
||||
{
|
||||
Name: "token",
|
||||
ResourceRef: []config.ResourceReference{
|
||||
{
|
||||
Name: "githubTokenCredentialsId",
|
||||
Type: "secret",
|
||||
},
|
||||
|
||||
{
|
||||
Name: "",
|
||||
Paths: []string{"$(vaultPath)/github", "$(vaultBasePath)/$(vaultPipelineName)/github", "$(vaultBasePath)/GROUP-SECRETS/github"},
|
||||
Type: "vaultSecret",
|
||||
},
|
||||
},
|
||||
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: true,
|
||||
Aliases: []config.Alias{{Name: "githubToken"}, {Name: "access_token"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return theMetaData
|
||||
}
|
16
cmd/githubCommentIssue_generated_test.go
Normal file
16
cmd/githubCommentIssue_generated_test.go
Normal file
@ -0,0 +1,16 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGithubCommentIssueCommand(t *testing.T) {
|
||||
|
||||
testCmd := GithubCommentIssueCommand()
|
||||
|
||||
// only high level testing performed - details are tested in step generation procedure
|
||||
assert.Equal(t, "githubCommentIssue", testCmd.Use, "command name incorrect")
|
||||
|
||||
}
|
80
cmd/githubCommentIssue_test.go
Normal file
80
cmd/githubCommentIssue_test.go
Normal file
@ -0,0 +1,80 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-github/v32/github"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type ghIssueCommentMock struct {
|
||||
issueComment *github.IssueComment
|
||||
issueID int64
|
||||
issueError error
|
||||
owner string
|
||||
repo string
|
||||
number int
|
||||
}
|
||||
|
||||
func (g *ghIssueCommentMock) CreateComment(ctx context.Context, owner string, repo string, number int, comment *github.IssueComment) (*github.IssueComment, *github.Response, error) {
|
||||
g.issueComment = comment
|
||||
g.owner = owner
|
||||
g.repo = repo
|
||||
g.number = number
|
||||
|
||||
issueComment := github.IssueComment{ID: &g.issueID, Body: comment.Body}
|
||||
|
||||
ghRes := github.Response{Response: &http.Response{Status: "200"}}
|
||||
if g.issueError != nil {
|
||||
ghRes.Status = "401"
|
||||
}
|
||||
|
||||
return &issueComment, &ghRes, g.issueError
|
||||
}
|
||||
|
||||
func TestRunGithubCommentIssue(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
t.Parallel()
|
||||
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
// init
|
||||
ghIssueCommentService := ghIssueCommentMock{
|
||||
issueID: 1,
|
||||
}
|
||||
config := githubCommentIssueOptions{
|
||||
Owner: "TEST",
|
||||
Repository: "test",
|
||||
Body: "This is my test body",
|
||||
Number: 1,
|
||||
}
|
||||
|
||||
// test
|
||||
err := runGithubCommentIssue(ctx, &config, nil, &ghIssueCommentService)
|
||||
|
||||
// assert
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, config.Owner, ghIssueCommentService.owner)
|
||||
assert.Equal(t, config.Repository, ghIssueCommentService.repo)
|
||||
assert.Equal(t, config.Body, ghIssueCommentService.issueComment.GetBody())
|
||||
assert.Equal(t, config.Number, ghIssueCommentService.number)
|
||||
})
|
||||
|
||||
t.Run("Error", func(t *testing.T) {
|
||||
// init
|
||||
ghIssueCommentService := ghIssueCommentMock{
|
||||
issueError: fmt.Errorf("error creating comment"),
|
||||
}
|
||||
config := githubCommentIssueOptions{
|
||||
Number: 1,
|
||||
}
|
||||
|
||||
// test
|
||||
err := runGithubCommentIssue(ctx, &config, nil, &ghIssueCommentService)
|
||||
|
||||
// assert
|
||||
assert.EqualError(t, err, "Error occurred when creating comment on issue 1: error creating comment")
|
||||
})
|
||||
}
|
@ -35,6 +35,7 @@ func GetAllStepMetadata() map[string]config.StepData {
|
||||
"gctsExecuteABAPUnitTests": gctsExecuteABAPUnitTestsMetadata(),
|
||||
"gctsRollback": gctsRollbackMetadata(),
|
||||
"githubCheckBranchProtection": githubCheckBranchProtectionMetadata(),
|
||||
"githubCommentIssue": githubCommentIssueMetadata(),
|
||||
"githubCreatePullRequest": githubCreatePullRequestMetadata(),
|
||||
"githubPublishRelease": githubPublishReleaseMetadata(),
|
||||
"githubSetCommitStatus": githubSetCommitStatusMetadata(),
|
||||
|
@ -74,6 +74,7 @@ func Execute() {
|
||||
rootCmd.AddCommand(KubernetesDeployCommand())
|
||||
rootCmd.AddCommand(XsDeployCommand())
|
||||
rootCmd.AddCommand(GithubCheckBranchProtectionCommand())
|
||||
rootCmd.AddCommand(GithubCommentIssueCommand())
|
||||
rootCmd.AddCommand(GithubCreatePullRequestCommand())
|
||||
rootCmd.AddCommand(GithubPublishReleaseCommand())
|
||||
rootCmd.AddCommand(GithubSetCommitStatusCommand())
|
||||
|
13
documentation/docs/steps/githubCommentIssue.md
Normal file
13
documentation/docs/steps/githubCommentIssue.md
Normal file
@ -0,0 +1,13 @@
|
||||
# ${docGenStepName}
|
||||
|
||||
## Prerequisites
|
||||
|
||||
You need to create a personal access token within GitHub and add this to the Jenkins credentials store.
|
||||
|
||||
Please see [GitHub documentation for details about creating the personal access token](https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/).
|
||||
|
||||
## ${docGenParameters}
|
||||
|
||||
## ${docGenConfiguration}
|
||||
|
||||
## ${docGenDescription}
|
@ -91,6 +91,7 @@ nav:
|
||||
- gctsExecuteABAPUnitTests: steps/gctsExecuteABAPUnitTests.md
|
||||
- gctsRollback: steps/gctsRollback.md
|
||||
- githubCheckBranchProtection: steps/githubCheckBranchProtection.md
|
||||
- githubCommentIssue: steps/githubCommentIssue.md
|
||||
- githubCreatePullRequest: steps/githubCreatePullRequest.md
|
||||
- githubPublishRelease: steps/githubPublishRelease.md
|
||||
- githubSetCommitStatus: steps/githubSetCommitStatus.md
|
||||
|
90
resources/metadata/githubcommentissue.yaml
Normal file
90
resources/metadata/githubcommentissue.yaml
Normal file
@ -0,0 +1,90 @@
|
||||
metadata:
|
||||
name: githubCommentIssue
|
||||
description: Comment on GitHub issues and pull requests.
|
||||
longDescription: |
|
||||
This step allows you to add comments to existing GitHub issues or pull requests.
|
||||
|
||||
Pull requests are considered similar to issues and thus adding a comment can be done to an existing pull request as well.
|
||||
This comes in very handy when you want to make developers aware of certain things during a PR voting process, for example.
|
||||
spec:
|
||||
inputs:
|
||||
secrets:
|
||||
- name: githubTokenCredentialsId
|
||||
description: Jenkins 'Secret text' credentials ID containing token to authenticate to GitHub.
|
||||
type: jenkins
|
||||
params:
|
||||
- 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: body
|
||||
description: Defines the content of the comment, e.g. using markdown syntax.
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
type: string
|
||||
mandatory: true
|
||||
- name: number
|
||||
description: Defines the number of the GitHub issue/pull request.
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
type: int
|
||||
mandatory: true
|
||||
- name: owner
|
||||
aliases:
|
||||
- name: githubOrg
|
||||
description: Name of the GitHub organization.
|
||||
resourceRef:
|
||||
- name: commonPipelineEnvironment
|
||||
param: github/owner
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
type: string
|
||||
mandatory: true
|
||||
- name: repository
|
||||
aliases:
|
||||
- name: githubRepo
|
||||
description: Name of the GitHub repository.
|
||||
resourceRef:
|
||||
- name: commonPipelineEnvironment
|
||||
param: github/repository
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STAGES
|
||||
- STEPS
|
||||
type: string
|
||||
mandatory: true
|
||||
- name: token
|
||||
aliases:
|
||||
- name: githubToken
|
||||
- name: access_token
|
||||
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
|
||||
secret: true
|
||||
resourceRef:
|
||||
- name: githubTokenCredentialsId
|
||||
type: secret
|
||||
- type: vaultSecret
|
||||
paths:
|
||||
- $(vaultPath)/github
|
||||
- $(vaultBasePath)/$(vaultPipelineName)/github
|
||||
- $(vaultBasePath)/GROUP-SECRETS/github
|
@ -141,6 +141,7 @@ public class CommonStepsTest extends BasePiperTest{
|
||||
'checkmarxExecuteScan', //implementing new golang pattern without fields
|
||||
'githubPublishRelease', //implementing new golang pattern without fields
|
||||
'githubCheckBranchProtection', //implementing new golang pattern without fields
|
||||
'githubCommentIssue', //implementing new golang pattern without fields
|
||||
'githubSetCommitStatus', //implementing new golang pattern without fields
|
||||
'kubernetesDeploy', //implementing new golang pattern without fields
|
||||
'piperExecuteBin', //implementing new golang pattern without fields
|
||||
|
11
vars/githubCommentIssue.groovy
Normal file
11
vars/githubCommentIssue.groovy
Normal file
@ -0,0 +1,11 @@
|
||||
import groovy.transform.Field
|
||||
|
||||
@Field String STEP_NAME = getClass().getName()
|
||||
@Field String METADATA_FILE = 'metadata/githubcommentissue.yaml'
|
||||
|
||||
void call(Map parameters = [:]) {
|
||||
List credentials = [
|
||||
[type: 'token', id: 'githubTokenCredentialsId', env: ['PIPER_token']]
|
||||
]
|
||||
piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user