Skip to content

Latest commit

 

History

History
115 lines (90 loc) · 9.05 KB

hip-0004.md

File metadata and controls

115 lines (90 loc) · 9.05 KB
hip title authors created type status
0004
Document backwards-compatibility rules
Marc Khouzam <[email protected]>
Matt Butcher <[email protected]>
2020-09-18
process
accepted

Abstract

Define and document the backwards-compatibility rules that apply to Helm minor and patch releases.

Motivation

Helm aims to strictly respect Semantic Versioning, where minor and patch releases must be 100% backwards compatible. Backwards compatibility implies that when moving to a new backwards-compatible release:

  • tools (such as Continuous Integration tools) using the helm CLI will not require any changes
  • programs using the Helm Go API will continue to compile

Some contributors to the Helm code base may not be comfortable with the details of what constitutes a compatibility-breaking change. Furthermore, in some cases, there can be a difference of opinion, even amongst the maintainers, on what constitutes such a change.

Having a well-defined, documented set of backwards-compatibility rules for the Helm code-base will allow to:

  • avoid compatibility-breaking changes being merged by mistake
  • guide contributors in understanding helm's backwards-compatibility requirements
  • remove any uncertainty when it comes to enforcing backwards compatibility
  • provide a basis for discussion and possible updates to how helm handles backwards compatibility

Rationale

The maintainers have agreed that a formal definition of Helm's backwards-compatibility rules would be beneficial.

Specification

The following compatibility rules will apply to helm minor and patch releases:

  • exported Go APIs will remain compatible as per this article

    • the exception to this rule is where Helm exposes Kubernetes APIs. Kubernetes APIs do not follow semantic versioning so Helm cannot enforce compatibility.
  • CLI commands and flags:

    • commands and flags are case-sensitive
    • commands and flags must not be removed
    • commands and flags must not be renamed
    • commands and flags must not be moved elsewhere in the command hierarchy
    • commands and flags cannot be "repurposed" to provide a different behavior than the original (even if deprecated)
    • flags must not change type. Exceptions are when the new type is a superset of the original type (e.g., int8 to int32, int to float, float to string)
    • these rules apply as much to the short name as to the long name of a flag, if present. Specifically, a short name cannot be changed in any way even if its long name is kept the same, and vice versa
  • CLI output:

    • the help text may change
    • the format of structured output (tables, JSON, YAML) must not change
    • errors can change if doing so increases their usability
    • a message containing a "bug" (including spelling errors, misinformation, or egregious grammar errors), can be fixed
    • return codes should not be changed unless they are incorrect
  • File formats (such as index.yaml, values.yaml, Chart.yaml):

    • No fields may be removed, added, or modified on the Chart.yaml file
    • No fields may be modified or removed in:
      • index.yaml
      • repositories.yaml
    • Any added fields must be accompanied by backward compatibility checks
    • No existing optional field can be made required (but a required field can be downgraded to optional)
    • If a field is added to a structured piece of data, it must be optional. No "new required" fields
    • We do not accept 3rd-party-specific fields (though we do facilitate them with things like annotations) This is grounds for rejecting an additive change in places where additions are allowed (e.g. like repositories.yaml)
  • Charts:

    • The handling of templates/ must not be changed
    • Reserved directory names (e.g. crds) must not be removed
    • No files or file types that are allowed may be changed to be disallowed
    • If an object or file type is added to a chart, it must also be optional (see requirements.yaml in Helm 2)
    • No files that were in the files object may be removed from the files object (in other words, a new file type may be added, but files cannot be removed from the files object just because they are instances of this new file type)
  • Templates (commands, functions, syntax, and variables):

    • Template functions cannot be removed
    • Return types of functions cannot change
    • A template function signature is additive (can add more parameters) if and only if the change is backwards compatible. E.g. sum int64 int64 can be changed to foo int64 int64 [int64] (where the new third parameter is optional). Likewise, print string could be changed to print any as long as any accepts a string and still treats it as it did before. But sum int64 int64 int64 could not be changed to sum int64 int64.
    • built-in directives, constants, and variables cannot be removed or changed in any way that would break an existing template
    • constants and variables that contain structured information cannot change the format of that structured information. (Example: if a built-in variable called ".Version" returned "helm-v1.2.3" it could not be changed to return "v1.2.3")
    • If a variable is changed to a function, it must not require any arguments or return a different return type than the original variable's value. (Example: If .Version was changed from a variable that returned v1.2.3, it can be changed to a function, but only if that function allows no parameters and when no parameters are specified, still returns in the format v1.2.3.
    • the template syntax cannot change except when the change is directly from the Go programming language (who has made such changes during Helm's history -- viz. adding the - whitespace chomp character and changing variables to become mutable).
    • occasionally, external template libraries or their dependencies have made breaking changes. We are now trying to avoid that.
  • Experimental Feature Flags:

    • From time to time, at the discretion of the core maintainers, new "experimental" features may be hidden behind one or more feature flags. An example of this in Helm 3.0.0 was the inclusion of experimental repository support.
    • Experimental features are not required to ensure backward compatibility for their feature set. (They cannot, however, break backward compatibility for other parts of Helm.) Thus, a new release of an existing experimental feature may break APIs, change its chart representations, or modify its command-line flags as long as it does not break the compatibility of non-experimental features.
    • Two experimental features are not required to be compatible with each other, though any feature must be compatible with all stable features before it can exit the experimental feature track.

Security implications

Compatibility rules may be broken or bent in the name of security. For example, if a flag once took an int64, but it was determined that doing so led to a buffer overflow, the datatype of that parameter could be changed.

In some cases, entire functions, template commands, etc. could be altered or removed if deemed absolutely necessary. Files formats can change as well. Of course, it should go without saying that we as maintainers should do our best to not have this happen if at all possible. This caveat is mainly to inform the end users that in extreme cases, we will break compatibility.

How to teach this

  • The list of compatibility rules should be published on helm.sh with a global explanation of the motivation behind to need to follow them
  • The list of compatibility rules should be used as a reference by maintainers when doing code reviews
  • During PR reviews, when appropriate, the reviewing maintainer should refer the contributor to the list of compatibility rules

Reference implementation

This HIP will serve as the document listing the backwards-compatibility rules.

Open issues

  • Should Go's experimental apidiff tool be used? The following issue gives a couple of ways to install it.
  • There has never been a consensus on messages that are user-facing and informal or non-informational (e.g. "Happy Helming"). I most often vote against these changes, while others have voted for them. [Butcher]
  • In the past, we have allowed formatting changes to structured formats (JSON, YAML) when such changes were not considered structural by the relevant specification. E.g. adding/removing whitespace in JSON documents. These days, we have been more resistant to that... but we have never explicitly said it is not allowed. [Butcher]
  • We do need to say something about "log" messages. We currently have no policy at all about log messages, and hence allow any changes to messages at the Debug and Warning levels. [Butcher]
  • Does breaking compatibility due to security require a major release?
  • Should the rules specifically mention the helm packages that must respect compatibility? (e.g., pkg for Go API, cmd for CLI)