github.com/joshdk/godel@v0.0.0-20170529232908-862138a45aee/apps/okgo/cmd/check.go (about)

     1  // Copyright 2016 Palantir Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package cmd
    16  
    17  import (
    18  	"fmt"
    19  	"io"
    20  	"os"
    21  	"strings"
    22  
    23  	"github.com/nmiyake/pkg/dirs"
    24  	"github.com/palantir/amalgomate/amalgomated"
    25  	"github.com/palantir/pkg/cli"
    26  	"github.com/palantir/pkg/cli/cfgcli"
    27  	"github.com/palantir/pkg/cli/flag"
    28  	"github.com/palantir/pkg/pkgpath"
    29  	"github.com/pkg/errors"
    30  
    31  	"github.com/palantir/godel/apps/okgo/checkoutput"
    32  	"github.com/palantir/godel/apps/okgo/checks"
    33  	"github.com/palantir/godel/apps/okgo/cmd/cmdlib"
    34  	"github.com/palantir/godel/apps/okgo/config"
    35  	"github.com/palantir/godel/apps/okgo/params"
    36  )
    37  
    38  const (
    39  	// releaseTagEnvVar the environment variable used to override the latest release tag that should be used in the
    40  	// default Go build context. See #72 for details.
    41  	releaseTagEnvVar = "OKGO_RELEASE_TAG"
    42  	packagesFlagName = "packages"
    43  )
    44  
    45  var packagesFlag = flag.StringSlice{
    46  	Name:     packagesFlagName,
    47  	Usage:    "Packages to check",
    48  	Optional: true,
    49  }
    50  
    51  func SetReleaseTagEnvVar(releaseTag string) error {
    52  	if releaseTag != "" {
    53  		if err := os.Setenv(releaseTagEnvVar, releaseTag); err != nil {
    54  			return err
    55  		}
    56  	}
    57  	return nil
    58  }
    59  
    60  func GetReleaseTagEnvVar() string {
    61  	return os.Getenv(releaseTagEnvVar)
    62  }
    63  
    64  func RunAllCommand(supplier amalgomated.CmderSupplier) cli.Command {
    65  	return cli.Command{
    66  		Name:  "runAll",
    67  		Usage: "Run all checks",
    68  		Flags: []flag.Flag{
    69  			packagesFlag,
    70  		},
    71  		Action: func(ctx cli.Context) error {
    72  			cfg, err := config.Load(cfgcli.ConfigPath, cfgcli.ConfigJSON)
    73  			if err != nil {
    74  				return err
    75  			}
    76  			wd, err := dirs.GetwdEvalSymLinks()
    77  			if err != nil {
    78  				return err
    79  			}
    80  			return DoRunAll(ctx.Slice(packagesFlagName), cfg, supplier, wd, ctx.App.Stdout)
    81  		},
    82  	}
    83  }
    84  
    85  func DoRunAll(pkgs []string, cfg params.OKGo, supplier amalgomated.CmderSupplier, wd string, stdout io.Writer) error {
    86  	var checksWithOutput []amalgomated.Cmd
    87  	for _, cmd := range cmdlib.Instance().Cmds() {
    88  		// if "omit" is true, skip the check
    89  		if cmdCfg, ok := cfg.Checks[cmd]; ok && cmdCfg.Skip {
    90  			continue
    91  		}
    92  
    93  		cmder, err := supplier(cmd)
    94  		if err != nil {
    95  			return errors.Wrapf(err, "%s is not a valid command", cmd.Name())
    96  		}
    97  
    98  		producedOutput, err := executeSingleCheckWithOutput(cmd, cmder, cfg, pkgs, wd, stdout)
    99  		if err != nil {
   100  			// indicates unexpected hard failure -- check returning non-0 exit code will not trigger
   101  			return errors.Wrapf(err, "check %s failed", cmd.Name())
   102  		}
   103  
   104  		if producedOutput {
   105  			checksWithOutput = append(checksWithOutput, cmd)
   106  		}
   107  	}
   108  
   109  	if len(checksWithOutput) != 0 {
   110  		return errors.Errorf("Checks produced output: %v", checksWithOutput)
   111  	}
   112  	return nil
   113  }
   114  
   115  func SingleCheckCommand(cmd amalgomated.Cmd, supplier amalgomated.CmderSupplier) cli.Command {
   116  	return cli.Command{
   117  		Name:  cmd.Name(),
   118  		Usage: "Run " + cmd.Name(),
   119  		Flags: []flag.Flag{
   120  			packagesFlag,
   121  		},
   122  		Action: func(ctx cli.Context) error {
   123  			cfg, err := config.Load(cfgcli.ConfigPath, cfgcli.ConfigJSON)
   124  			if err != nil {
   125  				return err
   126  			}
   127  			wd, err := dirs.GetwdEvalSymLinks()
   128  			if err != nil {
   129  				return err
   130  			}
   131  			if err := SetReleaseTagEnvVar(cfg.ReleaseTag); err != nil {
   132  				return err
   133  			}
   134  
   135  			cmder, err := supplier(cmd)
   136  			if err != nil {
   137  				return errors.Wrapf(err, "failed to create Cmder for %s", cmd.Name())
   138  			}
   139  
   140  			if producedOutput, err := executeSingleCheckWithOutput(cmd, cmder, cfg, ctx.Slice(packagesFlagName), wd, ctx.App.Stdout); producedOutput {
   141  				return fmt.Errorf("")
   142  			} else if err != nil {
   143  				return err
   144  			}
   145  			return nil
   146  		},
   147  	}
   148  }
   149  
   150  // executeSingleCheckWithOutput runs the specified check and outputs the result to stdOut. Returns true if the check
   151  // produced any output, false otherwise.
   152  func executeSingleCheckWithOutput(cmd amalgomated.Cmd, cmder amalgomated.Cmder, cfg params.OKGo, pkgs []string, wd string, stdout io.Writer) (bool, error) {
   153  	output, err := singleCheck(cmd, cmder, cfg, pkgs, wd, stdout)
   154  	if err != nil {
   155  		return false, err
   156  	}
   157  
   158  	producedOutput := len(output) != 0
   159  	if producedOutput {
   160  		outputLines := make([]string, len(output))
   161  		for i, currLine := range output {
   162  			outputLines[i] = currLine.String()
   163  		}
   164  		fmt.Fprintln(stdout, strings.Join(outputLines, "\n"))
   165  	}
   166  	return producedOutput, nil
   167  }
   168  
   169  func singleCheck(cmd amalgomated.Cmd, cmder amalgomated.Cmder, cfg params.OKGo, pkgs []string, cmdWd string, stdout io.Writer) ([]checkoutput.Issue, error) {
   170  	checker, err := checks.GetChecker(cmd)
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  
   175  	fmt.Fprintf(stdout, "Running %v...\n", cmd.Name())
   176  
   177  	if len(pkgs) == 0 {
   178  		// if no arguments were provided, run check on "all"
   179  		return checker.Check(cmder, cmdWd, cfg)
   180  	}
   181  
   182  	// convert arguments to packages
   183  	packages, err := pkgpath.PackagesFromPaths(cmdWd, pkgs)
   184  	if err != nil {
   185  		return nil, errors.Wrapf(err, "failed to convert arguments to packages: %v", pkgs)
   186  	}
   187  
   188  	// run check on specified packages
   189  	return checker.CheckPackages(cmder, packages, cfg)
   190  }