Skip to content

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

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. #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 #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 and the Open API 3.0 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":

// .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:

// .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:

{
    "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 path separated by a "#"

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

See here 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"

Activity

  1. bamurtaugh commented on Mar 30, 2022

    @bamurtaugh
    Member

    How does this experience differ from #22? Both seem to allow referencing / building off of another devcontainer.json, perhaps with this proposal allowing for referencing a specific property rather than entire file.

  2. greggroth commented on Mar 30, 2022

    @greggroth
    Author

    They solve basically the same problem, but in different ways. #22 uses a single top-level "extends" keyword to a file that is treated as a "parent" document with while this approach is more flexible, but consequently more complicated. I opened up separate issues for them since they aren't incompatible with one another.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    proposalStill under discussion, collecting feedback

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions