github.com/wmuizelaar/kpt@v0.0.0-20221018115725-bd564717b2ed/internal/gitutil/errors.go (about)

     1  // Copyright 2021 Google LLC
     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 gitutil
    16  
    17  import (
    18  	"regexp"
    19  	"strings"
    20  
    21  	"github.com/GoogleContainerTools/kpt/internal/errors"
    22  )
    23  
    24  // GitExecErrorType is used to enumerate git errors.
    25  type GitExecErrorType int
    26  
    27  const (
    28  	// Unknown is used when we can't classify an error into any of the other
    29  	// categories.
    30  	Unknown GitExecErrorType = iota
    31  	// GitExecutableNotFound means the git executable wasn't available.
    32  	GitExecutableNotFound
    33  	// UnknownReference means that provided reference (tag, branch) wasn't
    34  	// found
    35  	UnknownReference
    36  	// HTTPSAuthRequired means we try to access the repo using the https
    37  	// protocol, but the repo required authentication.
    38  	HTTPSAuthRequired
    39  	// RepositoryNotFound means the provided repo uri doesn't seem to point
    40  	// to a valid git repo.
    41  	RepositoryNotFound
    42  	// RepositoryUnavailable means we weren't able to connect to the provided
    43  	// uri.
    44  	RepositoryUnavailable
    45  )
    46  
    47  // GitExecError is an error type returned if kpt encounters an error while
    48  // executing a git command. It includes information about the command that
    49  // was executed and the output from git.
    50  type GitExecError struct {
    51  	Type    GitExecErrorType
    52  	Args    []string
    53  	Err     error
    54  	Command string
    55  	Repo    string
    56  	Ref     string
    57  	StdErr  string
    58  	StdOut  string
    59  }
    60  
    61  func (e *GitExecError) Error() string {
    62  	b := new(strings.Builder)
    63  	b.WriteString(e.Err.Error())
    64  	b.WriteString(": ")
    65  	b.WriteString(e.StdErr)
    66  	return b.String()
    67  }
    68  
    69  // AmendGitExecError provides a way to amend the GitExecError returned by
    70  // the GitLocalRunner.run command.
    71  func AmendGitExecError(err error, f func(e *GitExecError)) {
    72  	var gitExecErr *GitExecError
    73  	if errors.As(err, &gitExecErr) {
    74  		f(gitExecErr)
    75  	}
    76  }
    77  
    78  // determineErrorType looks at the output to stderr after executing a git
    79  // command and tries to categorize the error.
    80  func determineErrorType(stdErr string) GitExecErrorType {
    81  	switch {
    82  	case strings.Contains(stdErr, "unknown revision or path not in the working tree"):
    83  		return UnknownReference
    84  	case strings.Contains(stdErr, "could not read Username"):
    85  		return HTTPSAuthRequired
    86  	case strings.Contains(stdErr, "Could not resolve host"):
    87  		return RepositoryUnavailable
    88  	case matches(`fatal: repository '.*' not found`, stdErr):
    89  		return RepositoryNotFound
    90  	}
    91  	return Unknown
    92  }
    93  
    94  func matches(pattern, s string) bool {
    95  	matched, err := regexp.Match(pattern, []byte(s))
    96  	if err != nil {
    97  		// This should only return an error if the pattern is invalid, so
    98  		// we just panic if that happens.
    99  		panic(err)
   100  	}
   101  	return matched
   102  }