microsoft / vscode-dev-containers

NOTE: Most of the contents of this repository have been migrated to the new devcontainers GitHub org (https://github.com/devcontainers). See https://github.com/devcontainers/template-starter and https://github.com/devcontainers/feature-starter for information on creating your own!
https://aka.ms/vscode-remote
MIT License
4.72k stars 1.4k forks source link

Support versions in the `extensions` property besides publisher and ID (`devcontainer.json`) #1572

Open gsmachado opened 2 years ago

gsmachado commented 2 years ago

As the docs specify, the extensions property is an array of extension IDs that should be installed inside the container when it's created.

However, as a developer of devcontainer.json files, for multiple projects, sometimes is desired to set the specific version of an extension to be installed. This is super useful to ensure the reproducibility of development environments.

The problem is that, sometimes, container tools packaged in a container COULD BE incompatible with the latest and greatest version of certain VSCode extensions. For example, imagine that, for some reason, the underlying tools of that container are only compatible with redhat.java version 0.82.0 and not 1.10.2022080505. This creates a problem, given that every time the devcontainer.json is built on dev machines, the latest version of redhat.java is downloaded --> this is something not always desirable.

Therefore, what I suggest: change the specification of the extensions property and include the option for versioning (as an optional thing). This ensures backward compatibility.

For example:

"customizations": {
    "vscode": {
        "settings": {},
        "extensions": [
            "vsls-contrib.codetour",
            "redhat.java:0.82.0",
        ],
        "devPort": {}
        }
    }
}

while vsls-contrib.codetour will resolve to the latest version, redhat.java will be installed respecting the 0.82.0 extension version.

I went further and researched a bit on how VSCode plugins are downloaded from the marketplace. It seems all the information is available in the URL... for the example of redhat.java: https://redhat.gallery.vsassets.io/_apis/public/gallery/publisher/redhat/extension/java/0.82.0/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage.

I could not find the portion of code that evaluates the extensions property. If someone is kind enough to point that to me, I could even take a look at it, and better understand the complexity of changing things. 😄

jkeech commented 2 years ago

An alternative to this is to update the extensions to be local paths on disk inside the container, and then update the Dockerfile/image build to embed the exact version of the extension that you want. This solution also works for extensions that are not published on the marketplace.

For instance, your image can cache some extensions at /extensions. Then you can reference them in devcontainer.json as follows:

"customizations": {
    "vscode": {
        "extensions": [
            "/extensions/redhat.java-0.82.0.vsix"
        ]
    }
}
jkeech commented 2 years ago

It looks like the docs and the devcontainer schema are missing the fact that extensions can be referenced either by ID or by file path to the .vsix. The install-extension command in the VS Code server, which ends up getting called with the array of extensions in devcontainer.json, allows both formats: https://github.com/microsoft/vscode/blob/079c49ed1277fc42d8a49823dc6fbab473223503/src/vs/platform/extensionManagement/common/extensionManagementCLIService.ts#L110-L117