jberezanski / ChocolateyPackages

Chocolatey packages maintained by me
MIT License
83 stars 51 forks source link

Updating VisualStudio LTSC installations #139

Open DMaxter opened 1 year ago

DMaxter commented 1 year ago

When installing Visual Studio 2022 17.2.8 (LTSC) on a machine where Visual Studio 2022 17.2.7 (LTSC) was already installed, the installer exited with error, when using the DesiredVersion flag.

The channel for LTSC has .LTSC.<version> appended so it would fail to obtain a more recent version of the regular channel. We need to get the installed channel, if it exists, and use it, otherwise, we would follow the path it would follow without any changes

jberezanski commented 1 year ago

I don't have any experience with the LTSC releases, but I think I understand the problem.

First, some organizational matters:

Now, regarding the change itself. This:

$installed = Get-VisualStudioInstance | Where-Object { $_.ChannelId -like ($channelReference.ChannelId+ "*")}

may return more than one object when there are multiple VS instances installed (the user can have different products installed, such as Build Tools and Test Agent, or multiple installations of one product). Deeper in the extension, the Start-VSModifyOperation determines the set of VS instances to act upon, based on the product (defined by the package) and package parameters (such as --installPath). Only then can the function examine the installed instance to determine its actual channel.

I would also like to fully understand your scenario. Can you provide specific steps to reproduce the issue (let's say starting with a clean system with only Chocolatey installed)?

DMaxter commented 1 year ago

My team is deploying chocolatey packages of Visual Studio on a private repository, each one with the version we want, for example, Visual Studio 2022 Enterprise version 17.2.5 is one, version 17.2.7 is another (this one is LTSC) and 17.2.8 is another one (also LTSC).

For that we relied on your community package, but we are passing one more parameter to the Install-VisualStudio script, the DesiredProductVersion, allowing us to have a package that will install that specific version. We also change the installer URL and checksum for each package. We obtain these links from https://learn.microsoft.com/en-us/visualstudio/releases/2022/release-history

We recently moved from 17.2.5, a non-LTSC version to 17.2.7, an LTSC one, and everything went well. When then we wanted to updated it to 17.2.8 LTSC, the package failed to install. After some debugging, we verified that the ChannelId of the installed version was VisualStudio.17.Release.LTSC.17.2 and it was trying to install the LTSC version from Microsoft's VisualStudio.17.Release channel. When we appended by hand .LTSC.17.2 on Get-VSChannelReference we managed to install it. So, the fix we came up with was this one:

  1. We obtain the generated ChannelId
  2. We obtain all the installed ChannelIds
  3. We filter them to obtain only the one corresponding to the version we are installing (fixing the problem you raised above, also, knowing if it is BuildTools or TestAgent is only necessary later and will work just fine)
  4. If we had a channel that is very similar to the one we obtained from Get-VSChannelReference, i.e., may be exactly the same or can have the LTSC.<version> appended, we will use this one, otherwise, the default behaviour is respected

In order to replicate this behaviour you can do the following (with only Chocolatey installed):

  1. Create 3 packages of Visual Studio 2022 Enterprise, with the following DesiredProductVersion:
    • 17.2.32616.157 (this is 17.2.5, use the non-LTSC installer link, where the column Channel says Current)
    • 17.2.32802.462 (this is 17.2.7, here use the LTSC installer link, where the column Channel says LTSC 17.2)
    • 17.2.32901.213 (this is 17.2.8, here there is only an LTSC version)
  2. Have chocolatey-visualstudio.extension at hand
  3. Install them in the order above (from the oldest to the newest)
  4. Verify that you cannot install 17.2.8
  5. Apply the patch in this PR
  6. Verify that you can install 17.2.8
jberezanski commented 1 year ago

Thank you for the very detailed description, that really helps. I'll think about it over the weekend, but my instinctive reaction is that maybe it would be best to provide you an easy way to specify the exact channel id in your packages (since you are building them yourself anyway), eliminating the need for any channel guessing inside the extension.

jberezanski commented 1 year ago

I think I would like the default behavior of the packages/extension to be to assume the Current channel and only pick installed instances which refer to that channel when determining the instances to upgrade. This would be similar to how packages for VS Preview ignore VS "stable" and vice versa. Packages for channels other than Current would by default upgrade only the instances installed from that channel.

Still, the user always has the ability to override the instance selection logic by passing --installPath in package parameters. That way, for example, an existing installation from Current channel could be switched to LTSC by upgrading it using an LTSC package.

jberezanski commented 1 year ago

Also:

we are passing one more parameter to the Install-VisualStudio script, the DesiredProductVersion, allowing us to have a package that will install that specific version

Please note that the DesiredProductVersion parameter is used only for determining whether an existing VS instance should be upgraded (if installed version is equal or higher, it will not be upgraded) and for checking if the upgrade succeeded (after upgrade, the installed version should be equal to DesiredProductVersion). It does NOT influence the upgrade process in any way, i.e. the value of DesiredProductVersion has no effect on the VS version which will actually be installed.

The actually installed VS version is determined only by the channel manifest used during installation. The VS Installer may obtain the channel manifest from various sources:

Incidentally, this hints at one way of creating "fixed version" choco packages for any VS version - the package could contain an embedded channel manifest file, downloaded at some point from the default/evergreen url. Such a package would probably not be publishable on chocolatey.org (due to uncertain redistribution rights for the channel manifest), but would be perfectly OK for internal use. That way, if you just want to have packages which install a specific VS version in a deterministic way, you can create them from the Current channel and avoid the complications related to switching channels.

(Personally, I have an Azure DevOps pipeline, which runs daily, downloads the channel manifest from the Current channel and stores it in a Git repo. That way, I have the ability to easily go back to any VS version ever released in the Current channel, without relying on the fixed version installers published by MS.)

jberezanski commented 1 year ago
  1. Create 3 packages of Visual Studio 2022 Enterprise, with the following DesiredProductVersion: 17.2.32616.157 (this is 17.2.5, use the non-LTSC installer link, where the column Channel says Current) 17.2.32802.462 (this is 17.2.7, here use the LTSC installer link, where the column Channel says LTSC 17.2) 17.2.32901.213 (this is 17.2.8, here there is only an LTSC version)
  2. Have chocolatey-visualstudio.extension at hand
  3. Install them in the order above (from the oldest to the newest)

This currently fails for me even on the second package (when attempting to upgrade a Current 17.2.5 to LTSC 17.2.7): the VS Installer gets updated, but then hangs - two setup.exe processes remain running, but do nothing. When invoked with --package-parameters "--passive", the installer GUI ends up forever showing an unhelpful "Almost there...". FWIW, running the LTSC installer interactively does not provide an option to upgrade the Current installation to LTSC, so this may in general be an unsupported operation.

However, upgrading LTSC to LTSC should probably work. Attempting to perform it via the third package fails because the extension enters the "install a new instance" code path instead of the one for upgrading. I'm becoming more and more convinced now the extension should be told (by the package) about the channel. There is also already a bug here (or perhaps it can be called "unfinished implementation"), because channelId and productId can be passed via package parameters, but the install/update code path selection logic in Install-VisualStudio does not take package parameters into account (for determining the channel used for locating existing VS instances).

I have an idea for fixing this, while also at the same time implementing a feature I've been postponing for a long time, namely, the ability for a package to specify default values for package parameters (which will make it easier to create packages with embedded channel manifest files and/or bootstrappers - those packages will set installChannelUri/bootstrapperPath).

DMaxter commented 1 year ago

Yes, the bootstrapper installs the specific version, I forgot that.

When repeating the above procedures I also got stuck in the 17.2.7 installation, I don't know why, because it worked in the past. If I change manually the channel I will use, it allows me to install it, but it worked without this.

I have an idea for fixing this, while also at the same time implementing a feature I've been postponing for a long time, namely, the ability for a package to specify default values for package parameters (which will make it easier to create packages with embedded channel manifest files and/or bootstrappers - those packages will set installChannelUri/bootstrapperPath).

I'll be waiting for this :)

jberezanski commented 1 year ago

Implemented in extension 1.11.0 (currently in preview).

I've also added example LTSC packages as well as fixed version variants (packages which always install a specific VS version) of both Current and LTSC. I don't intend to publish them to chocolatey.org at this time, because I don't have the capacity to support them, but they can serve as a template for anyone making their own.

jberezanski commented 1 year ago

Here are example scripts from an "evergreen" package which installs the latest version from the LTSC 17.4 channel:

ChocolateyInstall.ps1


Install-VisualStudio `
    -PackageName 'visualstudio2022buildtools-ltsc17.4' `
    -ApplicationName 'Microsoft Visual Studio Build Tools 2022' `
    -Url 'https://download.visualstudio.microsoft.com/download/pr/0bb9a5f5-5481-4efe-92ab-cca29a90fa5e/d0806da38afe46b8476ec8f206edd304b1ca60891c2967604846d3cf761b4875/vs_BuildTools.exe' <# https://aka.ms/vs/17/release.ltsc.17.4/vs_buildtools.exe #> `
    -Checksum 'D0806DA38AFE46B8476EC8F206EDD304B1CA60891C2967604846D3CF761B4875' `
    -ChecksumType 'SHA256' `
    -InstallerTechnology 'WillowVS2017OrLater' `
    -Product 'BuildTools' `
    -VisualStudioYear '2022' `
    -Preview $false `
    -DefaultParameterValues @{ channelId = 'VisualStudio.17.Release.LTSC.17.4' }

ChocolateyUninstall.ps1

Remove-VisualStudioProduct `
    -PackageName 'visualstudio2022buildtools-ltsc17.4' `
    -Product 'BuildTools' `
    -VisualStudioYear '2022' `
    -Preview $false `
    -DefaultParameterValues @{ channelId = 'VisualStudio.17.Release.LTSC.17.4' }

And here are scripts from a "fixed version" package which always installs version 17.4.6 from this channel:

ChocolateyInstall.ps1

Install-VisualStudio `
    -PackageName 'visualstudio2022buildtools-ltsc17.4' `
    -ApplicationName 'Microsoft Visual Studio Build Tools 2022' `
    -Url 'https://download.visualstudio.microsoft.com/download/pr/d1ed8638-9e88-461e-92b7-4e29cc6172c3/38b09fc09ae9e590b73ae6752a0ebfd62579798969041bd341689273b842bc10/vs_BuildTools.exe' <# https://learn.microsoft.com/en-us/visualstudio/releases/2022/release-history #> `
    -Checksum '38B09FC09AE9E590B73AE6752A0EBFD62579798969041BD341689273B842BC10' `
    -ChecksumType 'SHA256' `
    -InstallerTechnology 'WillowVS2017OrLater' `
    -Product 'BuildTools' `
    -VisualStudioYear '2022' `
    -Preview $false `
    -DefaultParameterValues @{ channelId = 'VisualStudio.17.Release.LTSC.17.4'; installChannelUri = 'https://aka.ms/vs/17/release.ltsc.17.4/176788236_-978989559/channel' }

ChocolateyUninstall.ps1 (same as evergreen)

Remove-VisualStudioProduct `
    -PackageName 'visualstudio2022buildtools-ltsc17.4' `
    -Product 'BuildTools' `
    -VisualStudioYear '2022' `
    -Preview $false `
    -DefaultParameterValues @{ channelId = 'VisualStudio.17.Release.LTSC.17.4' }
jberezanski commented 1 year ago

Some more findings from the tests:

  1. The fixed version packages are perfectly capable of upgrading an existing older instance within the same channel and the result is as expected - the resulting version is the one defined in the package (not the latest from the channel).
  2. Although Microsoft does not support it and does not provide download links for the dedicated installers, it is possible to deterministically install a specific, older version of VS Community, using the generic installer (vs_Setup.exe), obtained from the link in the channel manifest. In fact, it is possible in this manner to install a specific version of any product from any channel, if only the download url for the channel manifest is known (and the channel manifest url can be extracted from the installers published by Microsoft, for example for VS Enterprise).
  3. It is not possible to use one channel to upgrade an instance installed from another channel. There is an explicit action in the VS Installer GUI (available also as modifySettings from the command line) to switch the update channel of an installed VS instance. There are some rules, however, for when the switch can be performed and to which channel. Also, from my personal testing, either the documentation is incomplete or the feature is buggy, because it does not always work reliably.