Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spec #147 - Support different release channels [released, beta, alpha] #1742

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/actions/spelling/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ AUrl
Aysnc
azurewebsites
badbit
Badlion
Baz
bcp
Beigi
Expand Down Expand Up @@ -133,7 +134,6 @@ GES
GESMBH
GHS
gity
Google
helplib
helplibrary
hhx
Expand Down Expand Up @@ -380,8 +380,6 @@ wesome
windir
windowsdeveloper
winerror
wingetcreate
wingetdev
winreg
withstarts
wn
Expand Down
12 changes: 12 additions & 0 deletions .github/actions/spelling/patterns.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer
# schema regex
"pattern": .*$

# spec parameters
author: .*$

# doc/ManifestSpecv1.0.md
^ShortDescription: Le nouveau.*$

Expand All @@ -48,5 +51,14 @@ REQUIRE\(RestHelper::GetRestAPIBaseUri\(".*"\) == L".*"
# URL escaped characters
\%[0-9A-F]{2}

# URLs
http(s){0,1}:\/\/.*\b

# Sample store product id for App Installer
9nblggh4nns1

# Google / google
[Gg]oogle

# Winget
[Ww]in[Gg]et(dev|create|bot)*
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
---
author: Kaleb Luedtke - Trenly <[email protected]>
created on: 2021-11-18
last updated: 2021-11-20
issue id: 147
---

# Release Channels

For [#147](https://github.com/microsoft/winget-cli/issues/147)

## Abstract

Several packages have different channels for releasing different versions of their software. The Windows Package Manager should be able to support packages of the same Package Identifier where the versions come from different release channels. The Windows Package Manager should be also able to inform a user about which channels are available.

## Inspiration

Some other package managers have this capability. In the current state, a new package identifier must be created for each release channel which can cause conflicts when the versions are *not* side-by-side compatible.

## Solution Design

### Manifest Structure
The Windows Package Manager manifest v1.1.0 schema has provided a key for declaring which channel an installer belongs to. However, this has the potential to make the installer manifests extremely complex when there are multiple release channels with multiple installers each.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, this appears to be an oversight on my part due to the too many things effect...

It really should have been in the version schema; maybe we can fix it by moving it to the correct location and using PackageChannel as the supported value. I think it could also work in the installer schema, so long as it is only allowed at the root, not on individual installers (I think it is but I don't 100% trust myself on a quick look at the JSON schema).

But if it is a single value, the location that it is defined is more for readability than the technical part. That is the route that was planned long ago, and it will probably be easier to stick with that than change course now.

Copy link
Contributor Author

@Trenly Trenly Nov 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that each installer should have a channel associated with it. The main issue I see here is that a single channel could have many many installers or just a single installer. Providing the support to have different channels as different installer manifests would remove this issue.

The key could potentially be left as it is to allow for the case where there is one installer for each channel too. It wouldn’t necessarily have to be at just the root level.

I think the biggest thing is that we align and understand what the best path forward is at the moment

> The `Channel` key should be removed from the manifest v1.1.0 schema.

Instead, the use of multiple installer manifest files will be used to define and manage the various channels available for a package in a way similar to locales. This will ensure that the client remains backwards compatible with old manifest versions, and will make the creation and maintenance of the various channels easier for contributors in the community repository. This will require a key be added to the manifest schema. Channels should not be compatible with singleton manifests.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything needs be compatible with any manifest representation, we just impose certain patterns on winget-pkgs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure what you mean by this comment. Is this just saying that singletons should support channels?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Manifests from any source, i.e. REST sources that don’t use the manifest schema, preindexed sources (which are generated from the YAML files but converted to a different format), and local (-m on a folder) manifests is what I think that means.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see; In that case, there still shouldn’t be an issue, since the rest sources should still be able to specify the channel, pre-indexed should work as it would just require them to support building from the proposed mutiple-installer-manifests yaml structure, and local would still be handled just fine since the CLI would be able to find the channels based on the filenames or the specified value in the manifest file

> The `DefaultChannel` key should be added to the manifest v1.1.0 schema for version manifests

An example of the manifest file structure, with installer channel manifests:
```raw
/manifests/g/Google/Chrome/1.0
| Google.Chrome.installer.beta.yaml
| Google.Chrome.installer.canary.yaml
| Google.Crome.installer.dev.yaml
| Google.Chrome.installer.Stable.yaml
| Google.Chrome.locale.en-US.yaml
| Google.Chrome.locale.nb-NO.yaml
| Google.Chrome.yaml
/manifests/g/Google/Chrome/2.0
| Google.Chrome.installer.canary.yaml
| Google.Crome.installer.dev.yaml
| Google.Chrome.locale.en-US.yaml
| Google.Chrome.locale.nb-NO.yaml
| Google.Chrome.yaml
Comment on lines +26 to +44
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem I have with this is that it relies on the folder/file naming setup of the community repo, which the client is not aware of (since it is designed to work with any source). How would channels be expressed without a schema field in REST sources, or other pre-indexed sources?

I think we keep the channel field in the schema, and add the DefaultChannel to the version schema. The channel can be given per installer entry, which I'm aware will get unwieldy (but hopefully we don't have to use it often enough for it to be a problem).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I’m not mistaken, for other sources, the channel would still be included in the package schema. Since the package schema is different than the manifest schema, I believe this would still be supported?

Either that, or I would suggest having it both ways. That way the community repo and other sources could still be kept relatively organized by taking advantage of splitting the manifests, but other sources which aren’t able to could still support channels

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original thought (pre multi-file manifests) was to have a structure like:

publisher\package\version
publisher\package\non-default-channel\version

With Channel being in the installer schema, your design can work too. I think it might be a bit more confusing though, as it is harder to see what is in each channel at a glance.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original thought (pre multi-file manifests) was to have a structure like:

publisher\package\version
publisher\package\non-default-channel\version

With Channel being in the installer schema, your design can work too. I think it might be a bit more confusing though, as it is harder to see what is in each channel at a glance.

That is the way it works currently, but based on the validation over at winget-pkgs, these would be completely separate package Identifiers. If I’m not mistaken, the whole point of channels is to combine package identifiers to be better representative of how packages are published, since some publishers do not allow side-by-side compatibility for different channels and so a user may not realize that Example.Package would be overwritten if they install Example.Package.Dev

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We would update winget-pkgs validation to handle non-empty channels in this way so that both would still be Example.Package.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would work too. If that is the preferred approach, I will update the spec. Just so long as we capture the work that is needed

```

To maintain backwards compatability, `null` should be treated as a valid `DefaultChannel`. If the default channel is not specified, `<PackageIdentifier>.installer.yaml` would be treated as the default. Additional channels may still be added to the package, and all functionality would still be present.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code already expects that an empty value is the default channel. Having a user defined default channel value will complicate things. I don't see the value in allowing it even if it was easy either.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One that I could think of is Ubuntu. Canonical.Ubuntu 16.04, 18.04, and 20.04 all have their own release cadence, but so does the un-versioned channel. In this case, 20.04 would make the most sense to be the default channel.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the thinking that the default channel will march forward with the latest release? So currently it would be 20.04 but when 22.04 is released it would change to that, while still leaving the 20.04 channel as is. I see the value there; if we used an empty channel then to achieve the same thing would require moving/renaming all of the manifests.

I think it still makes sense (and I think what you are saying the spec) to allow for the empty channel to be the default default. Then only allow for DefaultChannel when there is no empty channel.


An example of the manifest file structure when `DefaultChannel` is unset -
```raw
/manifests/7/7zip/7zip/1.0
| 7zip.7zip.installer.yaml
| 7zip.7zip.installer.Alpha.yaml
| 7zip.7zip.locale.en-US.yaml
| 7zip.7zip.yaml
/manifests/7/7zip/7zip/2.0
| 7zip.7zip.installer.Alpha.yaml
| 7zip.7zip.locale.en-US.yaml
| 7zip.7zip.yaml
```

### CLI Behavior
Where not specified by the user, the default release channel should be used/shown first or exclusively, then other channels in ASCII sort order. If the package manifest has a default channel specified and no versions of that package have an installer manifest matching the default channel, then the next available channel should be used/shown. Channels should be treated as *case-insensitive*.

The channel `Default` shall be treated as a reserved token. When used in commands, default should refer to the default channel specified in the version manifest. In command output, when the default channel is named, the name should be shown. If the default channel is null, then `Default` should be shown. Manifest validation should throw an error when `DefaultChannel` is `Default`

#### winget search
In order to avoid package duplication in search results, only the default channel should be shown unless otherwise specified. Users should be able to search for packages by release channel in addition to all other search filters.

Some valid searches:
```powershell
PS> winget search --channel <channel> # Return all packages which have a channel matching <channel>
PS> winget search --channel "" # Return all packages which have a null channel
PS> winget search <query> --channel <channel> # Return packages matching <query> which have a channel matching <channel>
PS> winget search --tag <tag> --channel <channel> # Return packages with a tag matching <tag> which have a channel matching <channel>
...
```

#### winget show
When the user specifies `--versions`, the versions for all channels along with the channels should be shown. The versions should be grouped by channel, sorted by channel, then sorted by version descending
When the user specifies `--channels`, the available channels for the package should be shown. If a package contains a named default channel and unnamed (null) channels, only the named channels should be shown
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following this part, but I assert that there should be only one empty channel, and any number of non-empty channels.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this goes back to your point about whether or not a named channel could or should be allowed to be default


#### winget install
When the user does not specify `--channel`, the default channel should be used. If the user does specify `--channel`, the specified channel should be used. The latest version for the channel should be installed, unless a user specified the version using the `--version` parameter. Additionally, the Windows Package Manager should record the package channel in some manner to ensure that upgrades to the package are found using the correct channel.

Optionally, the user should be able to specify the channel as part of the package identifier using the `@` symbol. For example, `winget install Google.Chrome@dev` would be equivalent to `winget install Google.Chrome --channel dev`
Trenly marked this conversation as resolved.
Show resolved Hide resolved

#### winget upgrade
When listing the packages available for upgrade, the Windows Package Manger should look only for packages matching the release channel of the installed package.
When installing packages available for upgrade, the Windows Package Manager should only install new versions matching the release channel of the installed package.

If the package channel cannot be determined, there are several options.
1) Ask the user for input.
2) Throw a warning and skip that package
3) Use the default channel for that package

The Windows Package Manager should never leave a package in a state where it cannot be upgraded simply because the package is unknown. To account for this, there must be some way for the user to specify a release channel. Therefore, when `winget upgrade --all` is used, and the release channel cannot be determined, a warning should be shown and the package should be skipped. For all other cases, the user should be asked to select a release channel on a per-package basis; the user's choice for that package should persist.

#### winget export/import
When exporting the list of installed packages, where possible, the release channel should be included with the export.
When importing the list of installed packages, where possible, the release channel should be honored. If the release channel is not able to be honored, a warning should be thrown, and the default release channel should be used
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think our default stance is to fail the import without doing anything if we know up front that we can't do what is asked.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thats a fair stance. I’ll update this if needed


### Settings
The user should be able to specify a set of preferred release channels in their settings file. The `channel` parameter should be added under `installBehavior`. The matching parameter is `--channel`. The order of the preferences should be considered when installing packages such that the first value is the highest preference.
```json
"installBehavior": {
"preferences": {
"locale": [ "en-US", "fr-FR" ],
"channel": ["alpha","beta","dev","canary","nightly"]
}
}
```

## UI/UX Design
### Searching for package version with release channel

```raw
PS> winget search Google.Chrome

Name Id Version Channel
-----------------------------------------------------------------------------
Google Chrome Google.Chrome 96.0.4664.45 Stable
Chrome Remote Desktop Host Google.ChromeRemoteDesktop 96.0.4664.39 Stable

PS> winget search Google.Chrome --channel dev

Name Id Version Channel
----------------------------------------------------
Google Chrome Google.Chrome 97.0.4692.20 Dev

PS> winget search Google --channel dev
Name Id Version Channel
-----------------------------------------------------------
Google Chrome Google.Chrome 97.0.4692.20 Dev
Android Studio Google.AndroidStudio 2020.3.1 dev
```

### Showing available release channels
```raw
# When all channels have defined names
PS> winget show Google.Chrome --channels
Found Google Chrome [Google.Chrome]
Channel
-------
Stable
Beta
Canary
Dev

# When the default channel is unnamed
PS> winget show 7zip.7zip --channels
Found 7-zip [7zip.7zip]
Channel
-------
Default
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the default channel is always "empty", then there is no need to have a reserved value or even show it in this case.

alpha

# When the default channel is named "Stable", but unnamed channels exist
PS> winget show Badlion.BadlionClient --channels
Found Badlion Client [Badlion.BadlionClient]
Channel
-------
Stable
```

### Showing available versions
```raw
PS> winget show Google.Chrome --versions
Found Google Chrome [Google.Chrome]
Version Channel
--------------------
96.0.4664.45 Stable
96.0.4667.49 Stable
96.0.4664.45 Beta
98.0.4708.0 Canary
97.0.4692.20 Dev
```

### Installing with release channel

When the channel is not the default channel, the channel name should be shown after the package identifier when installing or upgrading
```raw
PS> winget install Google.Chrome
Found Google Chrome [Google.Chrome] Version 96.0.4664.45
This application is licensed to you by its owner.
Microsoft is not responsible for, nor does it grant any licenses to, third-party packages.
Downloading https://dl.google.com/dl/chrome/install/googlechromestandaloneenterprise64.msi
██████████████████████████████ 78.8 MB / 78.8 MB
Successfully verified installer hash
Starting package install...
Successfully installed

PS> winget install Google.Chrome --channel dev
Found Google Chrome [Google.Chrome (Dev)] Version 97.0.4692.20
This application is licensed to you by its owner.
Microsoft is not responsible for, nor does it grant any licenses to, third-party packages.
Downloading https://dl.google.com/tag/s/dl/chrome/install/dev/googlechromedevstandaloneenterprise64.msi
██████████████████████████████ 78.4 MB / 78.4 MB
Successfully verified installer hash
Starting package install...
Successfully installed
```

### Listing installed packages
```raw
PS> winget list
Name Id Version Available Channel Source
-------------------------------------------------------------------------------------------------------------------------------
Microsoft Edge Microsoft.Edge 92.0.902.67 95.0.1020.53 winget
Microsoft Edge Update Microsoft Edge Update 1.3.147.37
App Installer Microsoft.DesktopAppInstaller_8wekyb3d8… 1.16.12653.0 Stable
Microsoft Edge Microsoft.MicrosoftEdge.Stable_8wekyb3d… 92.0.902.67 Stable
Google Chrome Google.Chrome 96.0.4664.45 97.0.4692.20 Dev winget
```

## Capabilities

Many packages use different structures for release channels. The Windows Package Manager should accommodate as many of these as is practicable.

### Accessibility

The Windows Package Manager has been built in such a way that screen readers will still provide audible output as the command is executed keeping the user informed of progress, warnings, and errors. This should have no direct impact on accessibility.

### Security

There should be no security impact directly, although we must remember that different sources may not guarantee the safety of packages. The Windows Package Manager community repository performs static and dynamic analysis, and in some cases additional manual validation before accepting a package.

### Reliability

The Windows Package Manager community repository has many packages that may be affected by release channels. The ease of keeping packages updated must be a consideration when designing other tools for creating and updating manifests.

### Compatibility

The current implementation for different release channels is to have separate package identifiers for each package. Packages which have channel-specific identifiers currently existing in the community repository /should/ be updated to use this feature, but will not be required to.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If they do not support side-by-side installation, they really should be moved to this pattern.

If they do support it, I think that is a whole other design spec to deal with them better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the point of channels is to have them be combined to a single identifier where possible. The packages which do support side by side are the best to have in the Example.Package / Example.Package.Dev format. It is when they do not support side by side that they should have the channel specified for the installer to ensure the proper channel is used for updates and installation


The current implementation of automation - specifically @wingetbot - does not have support for release channels. Any package which implements release channels will likely not be able to undergo automatic upgrade unless and until the automation considers this feature.

### Performance, Power, and Efficiency

The time needed to return search results is directly related to the number of packages included in the scope of the search. This feature will likely remove extraneous packages as they are combined into manifests with release channel support

## Potential Issues

* If a user installs a package outside of the Windows Package Manager, we may not be able to determine the channel. This has potential to cause conflicts if an attempt is made to upgrade applications from one channel to another.
* A package may have a `DefaultChannel` set and there be no versions available for the specified channel. When a user runs a search or upgrade for the package, the behavior may be unpredictable unless fallback behavior is accounted for in the implementation.
* Some packages may use multiple different names to refer to the same channel. Example - `Release`, `LTS`, `latest`, `current`, and `production` may all refer to the same channel. It may be wise to add an additional list parameter to the schema for `ChannelAliases`. This would allow the Windows Package Manager to identify when there is a matching package even though the user specified a release channel.

## Future considerations

* Implementation of the shorthand channel specifier may also allow for a shorthand version specifier such as `:`. This would enable something like `winget install Google.Chrome:96.0.4664.45@dev` for quick installation of specific versions and channels
Trenly marked this conversation as resolved.
Show resolved Hide resolved
* Applications which support side-by-side installation will remain under separate package identifiers under this schema. There may be a potential for the future to detect and allow for the side-by-side installations to be included in the release channels. This may need further investigation
* Release channels could potentially be used to mark packages as `portable` or `standalone` once [#182 - Support for installation of portable/standalone apps](https://github.com/microsoft/winget-cli/issues/182). This would be highly dependent upon the publisher and their release structure
## Resources

[Discussion from Trenly/winget-pkgs](https://github.com/Trenly/winget-pkgs/discussions/115)

[Indication of DefaultChannel Identifier](https://github.com/microsoft/winget-cli/discussions/1672#discussioncomment-1665516)

[Related Issue from Microsoft/winget-pkgs](https://github.com/microsoft/winget-pkgs/issues/16271)