Articulate how dependency versioning works

I've gone backwards and forwards on the design for dependency version
management.  However, I think what's written in this commit represents
a pretty sane "sweet spot" between all available options.

In a nutshell, anytime reference to a stack type in your Mufile is a
full-blown StackRef; in other words, it has a protocol (e.g., "https://"),
a base URL (e.g., "hub.mu.com/"), a name (e.g., "aws/s3/bucket"), and a
version ("@^1.0.6").  Each reference carries all of these components.

For convenience, you may omit the components.  In that case, Mu chooses
reasonable defaults:

* "https://" as the default protocol (or "git://"; this is TBD).
* "hub.mu.com/" as the default base URL.
* "@latest" as the default version number.

Note that a version can be "latest" to mean "tip", a specific SHA hash
to pin to a precise version, or a semantic version number/range.

I had originally shied away from specifying versions inline as you reference
stacks in your Mufile, and was leaning towards an explicit dependencies
section, however I was swayed for two reasons:

1. It's very common to only consume a given stack once in a file.  Needing
   to specify it in two places each time is verbose and violates DRY.

2. We have decided that each Mufile stands on its own and forms the unit
   of distribution.  I had previously thought we might move dependencies
   out of Mufiles into a "package manager" specification.  Lacking that,
   there is even less reason to call them out in a dedicated section.

Now, managing all these embedded version numbers across multiple stacks in
a single workspace would have been annoying.  (Many edits for a single
version bump.)  Instead, I've added provisions for storing this in your
workspace.yaml file.  The way it works is if any StackRef lacks a version
number, before defaulting to "@latest" we check the workspace.yaml file and,
if a default is found in there, we will use it.  For example:

        dependencies:
                aws/s3/bucket: ^1.0.6

The provision for pinning an entire namespace is also preserved.  E.g.:

        dependencies:
                aws/...: ^1.0.6
This commit is contained in:
joeduffy 2016-11-22 13:22:29 -08:00
parent 6f99088e2b
commit 83030685c3
2 changed files with 40 additions and 13 deletions

View file

@ -10,22 +10,20 @@ Stack may also carry arbitrary assets also (e.g., a program's `Dockerfile` and a
Each Stack reference (StackRef) combines a URL where the Stack may be downloaded from plus the desired version.
Each StackRef URL has a protocol, a base, and a name part; for example, in the Stack `https://hub.mu.com/aws/s3/bucket`,
`https://` is the protocol, `hub.mu.com/` is the base, and `aws/s3/bucket` is the name. It is most common to simply see
the name, because Mu treats `https://hub.mu.com/` as the default protocol and base, and will use it when not stated
explicitly. The way these URLs map to workspace paths during resolution is discussed later on.
Each StackRef URL has a protocol, a base URL, a name, and a version; for example, in the Stack
`https://hub.mu.com/aws/s3/bucket@^1.0.6`, `https://` is the protocol, `hub.mu.com/` is the base, `aws/s3/bucket` is the
name, and `^1.0.6` is the version. It is common to simply see the name, because Mu has reasonable defaults:
Note that StackRef URLs may reference multiple Stacks at once. To do so, the triple dot is appended to the URL to
be treated as a unit. For example, `https://hub.mu.com/aws/...` refers to the entirety of the available AWS Stacks.
* `https://` is the default protocol.
* `hub.mu.com/` is the default base URL.
* `latest` is the default version number (meaning "tip").
Each StackRef version may be either a specific Git SHA hash *or* a semantic version. If a specific hash, the reference
is said to be "pinned" to a precise version of that Stack. If a semantic version, the toolchain is given some "wiggle
room" in how it resolves the reference (in [the usual ways](https://yarnpkg.com/en/docs/dependency-versions)). Git tags
are used to specify semantic versions.
Each StackRef version may be either a specific Git SHA hash or a semantic version range. If a specific hash, the
reference is said to be "pinned" to a precise version of that Stack. If a semantic version, the toolchain is given some
"wiggle room" in how it resolves the reference (in [the usual ways](https://yarnpkg.com/en/docs/dependency-versions)).
Git tags are used to specify semantic versions. After compilation, all StackRefs will have been pinned.
It is possible, and indeed relatively common, for developers to use semantic versions in their Stacks but to pin
references by generating a so-called "lock file." This performs the usual dependency resolution process and saves the
output so that subsequent version updates are explicit, evident, and intentional.
The way these URLs map to workspace paths during resolution is discussed later on.
## Stack Resolution

View file

@ -218,6 +218,35 @@ define new, custom primitive Stacks for even richer functionality. TODO(joe): m
Finally, note that a companion namespace, `mu/x` also exists, that offers more cloud-neutral platform abstractions.
### Dependencies
We just saw that Service types can refer to other Stacks. That is done with a so-called StackRef, which is simply a
name that contains multiple parts:
* An optional protocol (e.g., `https://`).
* An optional base URL (e.g., `hub.mu.com/`, `github.com/`, etc).
* A required namespace and/or name part (e.g., `acmecorp/worker`, `aws/s3/bucket`, etc).
* An optional `@` followed by version number (e.g., `@^1.0.6`, `@6f99088`, `@latest`, etc).
If protocol and base URL are absent, Mu will default to `https://hub.mu.com/`. If the version is omitted, Mu will
default to `latest`, which just means "tip"; in other words, the most recent version is used at compile-time.
For Workspaces containing multiple Stacks, it can be advantageous to omit version information from your Stacks, and
instead place them into your `workspace.yaml` file's `dependencies` section. For example:
dependencies:
aws/s3/bucket: ^1.0.6
This helps to manage version numbers centrally which can be especially convenient when upgrading. Any StackRefs missing
version information will consult this workspace at compile-time. You may even pin an entire namespace this way:
dependencies:
aws/...: ^1.0.6
Note that the compiled `Mu.yaml` will always contain pinned versions, so that it stands on its own.
Please refer to [Mu Dependencies](deps.md) for more details on dependencies and how they are resolved.
### Visibility
At this point, a new concept is introduced: *visibility*. Visibility works much like your favorite programming