tools/eksDistroBuildToolingOpsTools/cmd/eksGoTool/cmd/backportIssue.go (127 lines of code) (raw):
package cmd
import (
"fmt"
"log"
"strings"
"time"
gogithub "github.com/google/go-github/v48/github"
"github.com/spf13/cobra"
"github.com/aws/eks-distro-build-tooling/tools/eksDistroBuildToolingOpsTools/pkg/constants"
"github.com/aws/eks-distro-build-tooling/tools/eksDistroBuildToolingOpsTools/pkg/github"
"github.com/aws/eks-distro-build-tooling/tools/eksDistroBuildToolingOpsTools/pkg/issueManager"
"github.com/aws/eks-distro-build-tooling/tools/eksDistroBuildToolingOpsTools/pkg/logger"
"github.com/aws/eks-distro-build-tooling/tools/eksDistroBuildToolingOpsTools/pkg/repoManager"
"github.com/aws/eks-distro-build-tooling/tools/eksDistroBuildToolingOpsTools/pkg/retrier"
)
const (
// Flag Names
backportVersionFlag = "backportVersions"
requestedByFlag = "requestedBy"
toplevelIssueIdFlag = "toplevelIssueId"
)
type backportIssueOptions struct {
backportVersions []string
requestedBy string
toplevelIssueId int
}
var bpOptions = &backportIssueOptions{}
func init() {
backportCmd.AddCommand(backportIssueCmd)
backportIssueCmd.Flags().IntVarP(&bpOptions.toplevelIssueId, toplevelIssueIdFlag, "i", 0, "Issue ID to be backported e.g. 254")
backportIssueCmd.Flags().StringVarP(&bpOptions.requestedBy, requestedByFlag, "r", "", "github username of the requester")
backportIssueCmd.Flags().StringSliceVarP(&bpOptions.backportVersions, backportVersionFlag, "b", nil, "to specify versions to backport use this flag. Multiple versions can be specified separated by commas. e.g. <ver>,<ver>,<ver>. If no option is supplied, default is to use MAINTAINED_EOL_VERSIONS file in eks-distro-build-tooling/golang/go")
requiredFlags := []string{
toplevelIssueIdFlag,
}
for _, flag := range requiredFlags {
if err := backportIssueCmd.MarkFlagRequired(flag); err != nil {
log.Fatalf("failed to mark flag %v as requred: %v", flag, err)
}
}
}
var backportIssueCmd = &cobra.Command{
Use: "issue",
Short: "Opens backport issues for top level github issue",
Long: "Opens issues to backport top level issue to EKS-Distro supported versions of Golang",
RunE: func(cmd *cobra.Command, args []string) error {
label := []string{"golang", "security"}
issueState := "open"
retrier := retrier.New(time.Second*380, retrier.WithBackoffFactor(1.5), retrier.WithMaxRetries(15, time.Second*30))
token, err := github.GetGithubToken()
if err != nil {
return fmt.Errorf("getting Github PAT from environment at variable %s: %v", github.PersonalAccessTokenEnvVar, err)
}
githubClient, err := github.NewClient(cmd.Context(), token)
if err != nil {
return fmt.Errorf("setting up Github client: %v", err)
}
if bpOptions.backportVersions == nil {
// When no version(s) are included as args, the default is to backport to all EOL versions
// tracked at eks-distro-build-tooling/golang/go/MAINTAINED_EOL_VERSIONS
// set up Repo Content Creator handler
repoManagerOpts := &repoManager.Opts{
SourceOwner: constants.AwsOrgName,
SourceRepo: constants.EksdBuildToolingRepoName,
}
rm := repoManager.New(retrier, githubClient, repoManagerOpts)
gfOpts := &repoManager.GetFileOpts{
Owner: constants.AwsOrgName,
Repo: constants.EksdBuildToolingRepoName,
Path: constants.EksGoSupportedVersionsPath,
Ref: nil,
}
f, err := rm.GetFile(cmd.Context(), gfOpts)
if err != nil {
return fmt.Errorf("getting file at %s: %v", gfOpts.Path, err)
}
fc, err := f.GetContent()
if err != nil {
return fmt.Errorf("getting file content from %v: %v", f.Name, err)
}
bpOptions.backportVersions = strings.Split(fc, "\n")
}
// set up Issue Creator handler
issueManagerOpts := &issueManager.Opts{
SourceOwner: constants.AwsOrgName,
SourceRepo: constants.EksdBuildToolingRepoName,
}
im := issueManager.New(retrier, githubClient, issueManagerOpts)
giOpts := &issueManager.GetIssueOpts{
Owner: constants.AwsOrgName,
Repo: constants.EksdBuildToolingRepoName,
Issue: bpOptions.toplevelIssueId,
}
toplevelIssue, err := im.GetIssue(cmd.Context(), giOpts)
if err != nil {
return fmt.Errorf("getting toplevel issue %v from %v: %v", giOpts.Issue, giOpts.Repo, err)
}
for _, ver := range bpOptions.backportVersions {
if ver != "" {
issueOpts := &issueManager.CreateIssueOpts{
Title: GenerateBackportIssueTitle(toplevelIssue, ver),
Body: GenerateBackportIssueBody(toplevelIssue, ver),
Labels: &label,
Assignee: nil,
State: &issueState,
}
_, err := im.CreateIssue(cmd.Context(), issueOpts)
if err != nil {
return fmt.Errorf("creating issue: %v", err)
}
}
}
return nil
},
}
func GenerateBackportIssueBody(ui *gogithub.Issue, ver string) *string {
b := strings.Builder{}
b.WriteString(fmt.Sprintf("A backport of issue %v to EKS Go %v was requested by @%v\n", *ui.HTMLURL, ver, bpOptions.requestedBy))
b.WriteString(fmt.Sprintf("%v", *ui.Body))
bs := b.String()
logger.V(4).Info("Created Issues Body: `%s`\n", bs)
return &bs
}
func GenerateBackportIssueTitle(ui *gogithub.Issue, ver string) *string {
t := strings.Builder{}
if *ui.Title != "" {
t.WriteString(fmt.Sprintf("%v - [eks go%v backport]", *ui.Title, ver))
}
ts := t.String()
logger.V(4).Info("Created Issues Title: `%s`\n", ts)
return &ts
}