Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Contractual Build Plan #12

Merged
merged 4 commits into from
Jul 10, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions text/0005-contractual-build-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Meta
[meta]: #meta
- Name: Contractual Build Plan
- Start Date: 2019-04-12
- CNB Pull Requests: (spec PR to follow)
- CNB Issues: (lifecycle issues to follow)

# Motivation
[motivation]: #motivation

This proposal suggests a new contract for generating the build plan and bill-of-materials that is easier to understand and more straightforward.
In addition, it fixes a critical design flaw in the current build plan mechanism: two buildpacks that require the same dependency at different stages (build vs. launch) will always result in unclear build failures due to the second request overriding the first request.

## Drawbacks of the current model

While the current build plan contract is superficially simple, buildpacks currently use it in ways that are occasionally difficult to understand or explain.
For example, some buildpacks "push" dependencies they plan to provide into the build plan, while other buildpacks "pull" dependencies they need from other buildpacks by placing them in the build plan.

Additionally, reading an incremental build plan during the detection phase isn't necessary to accomplish the current use cases for the build plan.

## Benefits of the proposed model

- Accounts for all current use cases while applying a tighter, "pull-only" contract
- Speeds up detection
- Simplifies writing modular buildpacks
- Easier to understand

# What it is
[what-it-is]: #what-it-is

This RFC proposes a breaking change to the build plan contract.
Changes would consist of modifications to the buildpack specification and lifecycle.

It affects buildpack developers who implement modular, interdependent buildpacks.

# How it Works
[how-it-works]: #how-it-works

## Overview of Changes

- `/bin/detect` no longer receives a build plan on stdin.
- In `/bin/detect`, buildpacks contribute two sections to the build plan: `requires` and `provides`
- Every required dependency must be provided for detection to pass.
- Every provided dependency must be required for detection to pass.
- If an optional buildpack provides a dependency that is not required, it is excluded from consideration.
- If an optional buildpack requires a dependency that is not provided, it is excluded from consideration.
- Multiple buildpacks may require or provide the same dependency.
- `/bin/build` no longer receives a build plan on stdin.
- `/bin/build`'s build plan argument contains required dependencies that it provides.
- `/bin/build` may refine its build plan to contain additional dependency metadata.
- `/bin/build` may remove all entries for a dependency in its build plan to allow a subsequent buildpack to provide that dependency.

## Examples

### Build Plan Contributions during Detection

Node Engine Buildpack:
```toml
[[provides]]
name = "nodejs"
```

NPM Buildpack:
```toml
[[requires]]
name = "nodejs"
version = "1.x"
[requires.metadata]
something = "12"

[[requires]]
name = "node_modules"

[[provides]]
name = "node_modules"
```

### Build Plan Input during Build

Node Engine Buildpack:
```toml
[[nodejs]]
version = "1.x"
[nodejs.metadata]
something = "12"
```

NPM Buildpack:
```toml
[[node_modules]]
```

## Bill-of-Materials

When combined:
```toml
[[nodejs]]
version = "1.2.3"
[nodejs.metadata]
something = "12"
arch = "x86_64"

[[node_modules]]
packages = ["..."]
```

# Unanswered Questions
[questions]: #questions

Should we provide an alternative version of `[[require]]` that also provides?
Alternatively, should `[[require]]` have a `provide = true` option?

# Drawbacks
[drawbacks]: #drawbacks

It's no longer possible to push structured data to subsequent buildpacks during detection.

# Alternatives
[alternatives]: #alternatives

Keeping the current build plan mechanism.