devcontainers / spec

Development Containers: Use a container as a full-featured development environment.
https://containers.dev
Creative Commons Attribution 4.0 International
3.61k stars 231 forks source link

Proposal: Feature dependsOn options customization #467

Open rubensa opened 6 months ago

rubensa commented 6 months ago

As for now, you can define that a feature dependsOn another feature but you are "forced" to specify all options that should be used in the "parent" feature. On the other hand, you can specify that the new feature should be installed after other feature, by specifying installsAfter but the other feature is not installed if the user does not specify it in devcontainer.json.

The problem is that you can't allow the user to specify the options for the "parent" feature and, at the same time, "force" that feature to be installed before the dependent feature (with the user specified configuration, if he specified it).

For example:

You could also use installAfter so the user can configure nvm to specify the version he wants to install, but the problem here is that, if the user do not specify the nvm feature, it is not "automatically" installed.

{
  "id": "node-nvm",
  "version": "0.0.1",
  "name": "Node.js (via nvm)",
  "description": "Installs Node.js using nvm (Node Version Manager).",
  "options": {
    "version": {
      "type": "string",
      "proposals": [
        "node",
        "18",
        "16",
        "14"
      ],
      "default": "node",
      "description": "Select or enter a Node.js version to install"
    }
  },
  "installsAfter": [
    "./local-features/nvm"
  ]
}

There might be two approaches here to solve the problem:

To me, the second one allows for more flexibility. The user is allowed to specify how to install nvm so the node-nvm uses that config but, if the user does not explicitly specify a nvm configuration the one specified in node-nvm dependsOn configuration should be used.

A third approach might be the combination of both. Allow the options "pass-throw" but only apply that config if the user did not already configured the "parent" feature.

joshspicer commented 5 months ago

Thank you for the detailed outline of your thoughts! I totally agree that there's room for improvement here.

Approach (1) seems to be a really good solution/compromise here, as it unblocks "passing down" options to dependencies while still tightly coupling the child Feature to its parent. Users are able to choose if a child's option(s) are customizable OR if they should be "frozen" with this given Feature release. Of course, with each Feature release that dependency's options could be updated.

My fear with approach (2) is that it could make it easier for a user to accidentally select incompatible child/parent Features without realizing the implication (ie: A user may not realize that a dependency exists and overrides it)

rubensa commented 5 months ago

Yes, the only thing here is that, in case of (1), to give flexibility, the amount of options to be redefined (to be passed -throw) might be huge (depending on the combination of both extension options).