package mutator import ( "context" "fmt" "regexp" semver "github.com/Masterminds/semver/v3" "github.com/databricks/cli/bundle" "github.com/databricks/cli/internal/build" "github.com/databricks/cli/libs/diag" ) func VerifyCliVersion() bundle.Mutator { return &verifyCliVersion{} } type verifyCliVersion struct { } func (v *verifyCliVersion) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnostics { // No constraints specified, skip the check. if b.Config.Bundle.DatabricksCliVersion == "" { return nil } constraint := b.Config.Bundle.DatabricksCliVersion if err := validateConstraintSyntax(constraint); err != nil { return diag.FromErr(err) } currentVersion := build.GetInfo().Version c, err := semver.NewConstraint(constraint) if err != nil { return diag.FromErr(err) } version, err := semver.NewVersion(currentVersion) if err != nil { return diag.Errorf("parsing CLI version %q failed", currentVersion) } if !c.Check(version) { if version.Prerelease() == "dev" && version.Major() == 0 { return diag.Warningf("Ignoring Databricks CLI version constraint for development build. Required: %s, current: %s", constraint, currentVersion) } return diag.Errorf("Databricks CLI version constraint not satisfied. Required: %s, current: %s", constraint, currentVersion) } return nil } func (v *verifyCliVersion) Name() string { return "VerifyCliVersion" } // validateConstraintSyntax validates the syntax of the version constraint. func validateConstraintSyntax(constraint string) error { r := generateConstraintSyntaxRegexp() if !r.MatchString(constraint) { return fmt.Errorf("invalid version constraint %q specified. Please specify the version constraint in the format (>=) 0.0.0(, <= 1.0.0)", constraint) } return nil } // Generate regexp which matches the supported version constraint syntax. func generateConstraintSyntaxRegexp() *regexp.Regexp { // We intentionally only support the format supported by requirements.txt: // 1. 0.0.0 // 2. >= 0.0.0 // 3. <= 0.0.0 // 4. > 0.0.0 // 5. < 0.0.0 // 6. != 0.0.0 // 7. 0.0.* // 8. 0.* // 9. >= 0.0.0, <= 1.0.0 // 10. 0.0.0-0 // 11. 0.0.0-beta // 12. >= 0.0.0-0, <= 1.0.0-0 matchVersion := `(\d+\.\d+\.\d+(\-\w+)?|\d+\.\d+.\*|\d+\.\*)` matchOperators := `(>=|<=|>|<|!=)?` return regexp.MustCompile(fmt.Sprintf(`^%s ?%s(, %s %s)?$`, matchOperators, matchVersion, matchOperators, matchVersion)) }