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  }