github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/maintenance/migratestatus/migratestatus.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "flag" 21 "fmt" 22 "os" 23 "regexp" 24 25 "github.com/pkg/errors" 26 "github.com/sirupsen/logrus" 27 28 "k8s.io/test-infra/maintenance/migratestatus/migrator" 29 "k8s.io/test-infra/prow/config/secret" 30 prowflagutil "k8s.io/test-infra/prow/flagutil" 31 "k8s.io/test-infra/prow/logrusutil" 32 ) 33 34 type options struct { 35 org, repo string 36 copyContext, moveContext, retireContext, destContext string 37 descriptionURL string 38 continueOnError, dryRun bool 39 github prowflagutil.GitHubOptions 40 branchFilterRaw string 41 branchFilter *regexp.Regexp 42 } 43 44 func gatherOptions() options { 45 o := options{} 46 fs := flag.NewFlagSet(os.Args[0], flag.ExitOnError) 47 48 fs.StringVar(&o.org, "org", "", "The organization that owns the repo.") 49 fs.StringVar(&o.repo, "repo", "", "The repo needing status migration.") 50 fs.BoolVar(&o.dryRun, "dry-run", true, "Run in dry-run mode, performing no modifying actions.") 51 fs.BoolVar(&o.continueOnError, "continue-on-error", false, "Indicates that the migration should continue if context migration fails for an individual PR.") 52 53 fs.StringVar(&o.copyContext, "copy", "", "Indicates copy mode and specifies the context to copy.") 54 fs.StringVar(&o.moveContext, "move", "", "Indicates move mode and specifies the context to move.") 55 fs.StringVar(&o.retireContext, "retire", "", "Indicates retire mode and specifies the context to retire.") 56 fs.StringVar(&o.destContext, "dest", "", "The destination context to copy or move to. For retire mode this is the context that replaced the retired context.") 57 fs.StringVar(&o.descriptionURL, "description", "", "A URL to a page explaining why a context was migrated or retired. (Optional)") 58 59 fs.StringVar(&o.branchFilterRaw, "branch-filter", "", "A regular expression which the PR target branch must match to be modified. (Optional)") 60 61 o.github.AddFlags(fs) 62 fs.Parse(os.Args[1:]) 63 return o 64 } 65 66 func (o *options) Validate() error { 67 if o.org == "" { 68 return errors.New("'--org' must be set.\n") 69 } 70 if o.repo == "" { 71 return errors.New("'--repo' must be set.\n") 72 } 73 74 if o.destContext == "" && o.retireContext == "" { 75 return errors.New("'--dest' is required unless using '--retire' mode.\n") 76 } 77 78 if o.descriptionURL != "" && o.copyContext != "" { 79 return errors.New("'--description' URL is not applicable to '--copy' mode") 80 } 81 82 var optionCount int 83 if o.copyContext != "" { 84 optionCount++ 85 } 86 if o.moveContext != "" { 87 optionCount++ 88 } 89 if o.retireContext != "" { 90 optionCount++ 91 } 92 if optionCount != 1 { 93 return errors.New("Exactly one mode must be specified [--copy|--retire|--move].") 94 } 95 96 if err := o.github.Validate(o.dryRun); err != nil { 97 return err 98 } 99 100 expr, err := regexp.Compile(o.branchFilterRaw) 101 if err != nil { 102 return fmt.Errorf("invalid --branch-filter regular expression: %v", err) 103 } 104 o.branchFilter = expr 105 106 return nil 107 } 108 109 func main() { 110 o := gatherOptions() 111 if err := o.Validate(); err != nil { 112 logrus.WithError(err).Fatal("Invalid options") 113 } 114 115 logrus.SetFormatter( 116 logrusutil.NewDefaultFieldsFormatter(nil, logrus.Fields{"component": "migratestatus"}), 117 ) 118 119 secretAgent := &secret.Agent{} 120 if o.github.TokenPath != "" { 121 if err := secretAgent.Start([]string{o.github.TokenPath}); err != nil { 122 logrus.WithError(err).Fatal("Error starting secrets agent.") 123 } 124 } 125 126 githubClient, err := o.github.GitHubClient(secretAgent, o.dryRun) 127 if err != nil { 128 logrus.WithError(err).Fatal("Error getting GitHub client.") 129 } 130 131 var mode *migrator.Mode 132 if o.copyContext != "" { 133 mode = migrator.CopyMode(o.copyContext, o.destContext) 134 } 135 if o.moveContext != "" { 136 mode = migrator.MoveMode(o.moveContext, o.destContext, o.descriptionURL) 137 } 138 if o.retireContext != "" { 139 mode = migrator.RetireMode(o.retireContext, o.destContext, o.descriptionURL) 140 } 141 142 // Note that continueOnError is false by default so that errors can be addressed when they occur 143 // instead of blindly continuing to the next PR, possibly continuing to error. 144 m := migrator.New(*mode, githubClient, o.org, o.repo, o.branchFilter.MatchString, o.continueOnError) 145 if err := m.Migrate(); err != nil { 146 logrus.WithError(err).Fatal("Error during status migration") 147 } 148 os.Exit(0) 149 }