get.porter.sh/porter@v1.3.0/pkg/schema/check-strategy.go (about)

     1  package schema
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/Masterminds/semver/v3"
     8  )
     9  
    10  // CheckStrategy is an enum of values for handling schemaVersion
    11  // comparisons of two resources. Allowed values are: CheckStrategyExact,
    12  // CheckStrategyMinor, CheckStrategyMajor, CheckStrategyNone.
    13  type CheckStrategy string
    14  
    15  const (
    16  	// CheckStrategyExact requires that resource schemaVersion values exactly match the supported schema version.
    17  	CheckStrategyExact CheckStrategy = "exact"
    18  
    19  	// CheckStrategyMinor requires that resource schemaVersion values match the MAJOR.MINOR portion of the supported schema version.
    20  	CheckStrategyMinor CheckStrategy = "minor"
    21  
    22  	// CheckStrategyMajor requires that resource schemaVersion values exactly match the MAJOR portion of the supported schema version.
    23  	CheckStrategyMajor CheckStrategy = "major"
    24  
    25  	// CheckStrategyNone ignores the resource schemaVersion. Errors will most likely ensue but have fun!
    26  	CheckStrategyNone CheckStrategy = "none"
    27  )
    28  
    29  // ErrInvalidSchemaVersion is used when the schemaVersion of two resources do not match exactly.
    30  var ErrInvalidSchemaVersion = errors.New("invalid schema version")
    31  
    32  // ValidateSchemaVersion checks the specified schema version against the supported version,
    33  // returning if the result is a warning only. Warnings are returned when the versions are not an exact match.
    34  // A warning is not returned when CheckStrategyNone is used.
    35  func ValidateSchemaVersion(strategy CheckStrategy, supported *semver.Constraints, specified string, defaultVersion *semver.Version) (bool, error) {
    36  	if specified == "" {
    37  		specified = "(none)"
    38  	}
    39  	baseMessage := fmt.Errorf("the schema version is %s but the supported schema version is %s. See https://porter.sh/reference/file-formats/#supported-versions for more details: %w",
    40  		specified, supported, ErrInvalidSchemaVersion)
    41  
    42  	specifiedV, err := semver.NewVersion(specified)
    43  	if err != nil {
    44  		isWarning := strategy == CheckStrategyNone
    45  		return isWarning, fmt.Errorf("%s is not a valid semantic version: %w", specified, ErrInvalidSchemaVersion)
    46  	}
    47  
    48  	isSchemaVersionSatisfied := supported.Check(specifiedV)
    49  	switch strategy {
    50  	case CheckStrategyNone:
    51  		// this strategy always passes
    52  	case CheckStrategyExact:
    53  		// Check if the schema version satisfies the supported version range
    54  		if isSchemaVersionSatisfied {
    55  			return false, nil
    56  		} else {
    57  			return false, baseMessage
    58  		}
    59  	case CheckStrategyMinor:
    60  		// Check if the schema version matches the MAJOR.MINOR version number of the currently supported (default) schema version
    61  		supportedMinor, _ := semver.NewConstraint(fmt.Sprintf("~%d.%d.0-0", defaultVersion.Major(), defaultVersion.Minor()))
    62  		isMinorMatch := supportedMinor.Check(specifiedV)
    63  		if !isMinorMatch {
    64  			return false, fmt.Errorf("the schema version MAJOR.MINOR values do not match: %w", baseMessage)
    65  		}
    66  	case CheckStrategyMajor:
    67  		// Check if the schema version matches the MAJOR version number of the currently supported (default) schema version
    68  		supportedMajor, _ := semver.NewConstraint(fmt.Sprintf("^%d.0.0-0", defaultVersion.Major()))
    69  		isMajorMatch := supportedMajor.Check(specifiedV)
    70  		if !isMajorMatch {
    71  			return false, fmt.Errorf("the schema version MAJOR values do not match: %w", baseMessage)
    72  		}
    73  	default:
    74  		return false, fmt.Errorf("unknown schema.CheckStrategy %v", strategy)
    75  	}
    76  
    77  	if isSchemaVersionSatisfied {
    78  		return false, nil
    79  	} else {
    80  		// Even if the check passed, print a warning if it wasn't strictly supported
    81  		return true, fmt.Errorf("WARNING: %w", baseMessage)
    82  	}
    83  }