devcontainers / devcontainers/spec

Addition of "$ref" property to enable flexible configuration composition

Open
#23 2 comments 3 reactions 0 assignees View on GitHub
proposal
Dominant language
No language data
Stars
5.7k
Forks
496
PR merge metrics
No merged PRs in 30d

Description

# Problem

Multiple teams collaborating on a common codebase may have different dependency or setup needs and currently this is done by sharing a single `devcontainer.json` configuration with all of their individual needs combined. https://github.com/microsoft/dev-container-spec/issues/6 describes support for multiple configuration files, but there isn't set a way to consolidate the shared configuration into a single file.

A simpler approach to solving this problem is proposed in https://github.com/microsoft/dev-container-spec/issues/22 while this aims to be a more complete solution. However, it's unclear if this level of support is truly necessary.

# Proposed Solution

Taking influence from [JSON Schema](https://json-schema.org/understanding-json-schema/structuring.html#ref) and the [Open API 3.0](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#referenceObject) specs, a special property named "$ref" would allow importing all or part of a referenced document. Here is an example:

Given a file "defaults.json":

```json5
// .devcontainer/defaults.json
{
"name": "microsoft/foo",
"extensions": [
"/root/hello-githug.vsix"
],
"forwardPorts": [80, 5432]
"hostRequirements": {
"storage": "64gb",
"memory": "32gb"
},
"portsAttributes": {
"80": {
"label": "web"
},
"5432": {
"label": "postgres"
}
}
}
```

If a team would like to introduce a team-specific configuration that adds ports for Redis, they can add a new configuration:

```json5
// .devcontainer/redis-team.json
{
"$ref": "defaults",
"extensions": [],
"forwardPorts": [ { "$ref": "defaults#/forwardPorts" }, 6379], // Explicit merge behavior
"hostRequirements": {
"memory": "64gb" // Require more memory
},
"portAttributes": {
"$ref": "defaults#/portAttributes", // Explicit merge behavior
"6379": {
"label": "redis"
}
}
}
```

Resulting in a final configuration:

```json5
{
"name": "microsoft/foo",
"extensions": [],
"forwardPorts": [80, 5432, 6379],
"hostRequirements": {
"storage": "64gb",
"memory": "64gb"
},
"portAttributes": {
"80": {
"label": "web"
},
"5432": {
"label": "postgres"
}
"6379": {
"label": "redis"
}
}
}
```

## Allowed Values for $ref

The value of a `$ref` contains a file and optionally a [JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901) path separated by a "#"

- Import an entire document: "default", "ports.json",
- Import the "forwardPorts" value: "defaults.json#/forwardPorts"

See [here](https://gregsdennis.github.io/Manatee.Json/usage/pointer.html) for more examples of JSON Pointer paths.

**Remote Reference:**
- File in the same directory, extension optional: `"document"`
- File in the same directory with extension: `"document.json"`
- File in a subdirectory: `"defaults/ports.json"`
- File in a parent directory: `"../other/defaults.json"`

**URL Reference:**
- File at a URI: `"https://github.com/microsoft/foo/blob/master/.devcontainer/devcontainer.json"`
- File at a URI: `"https://example.com/configuration.json"`

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.