First, we want to say thank you. Your contribution is highly valued. And we appreciate the time you have taken to get here and read this document. Let's start out with a few definitions to help you understand our vocabulary.
Manifests are the YAML files in this repository containing the metadata used by the Windows Package Manager to install and upgrade software on Windows 10. There are thousands of these files partitioned under the manifests directory. We've had to partition the directory structure so you don't have to scroll as much in the github.com site when you are looking for a manifest.
Think of a package as an application or a program. We use a "PackageIdentifier" to represent a unique package. These are generally in the form of Publisher.Package
. Sometimes you might see additional values separated by a second period. We will explain why a little bit later.
Package versions are associated with a specific release. In some cases you will see a perfectly formed semantic version number, and in other cases you might see something different. These may be date driven, or they might have other characters with some package specific meaning. The YAML key for a package version is "PackageVersion".
Once you have determined the "PackageIdentifier" and the "PackageVersion" it is possible to know the proper location for the manifest. We will use Microsoft Windows Terminal version 1.6.10571.0 for our example.
manifests / m / Microsoft / WindowsTerminal / 1.6.10571.0
The partition directory is determined by taking the first letter from the "PackageIdentifier" in lower case. The next directory must match the first segment of the "PackageIdentifier" (case sensitive) up to the first period. This pattern continues until a directory has been created for each section of the "PackageIdentifier" (case sensitive) separated by a period. The last directory must match the "PackageVersion".
Before you invest the time to generate and submit a manifest, you should check to see if the package already exists. Start out with winget search <package>
. If that doesn't yield anything, try a quick search using the search box in the top left corner of GitHub for the package "In this repository". If you still don't find anything, finally check to see if there is already a PR for the package by putting the package in the filters box, and be sure to remove the "is:pr is:open" filters.
You should take a look at our Manifest Specification. Don't worry. If this is starting to look too complicated you can create a new Issue and select Package Request/Submission 👀.
Manifests submitted to the Windows Package Manager Community Repository should be submitted as a multi-file manifest. The minimum required files are a version file, a defaultLocale file and an installer file.
Once you have a package in mind that doesn't already exist in the repository, you can now start creating your package manifest. We recommend using the Windows Package Manager Manifest Creator (a.k.a Winget-Create) to help you generate your manifest. Winget-Create is a command line tool that will prompt you for relevant metadata related to your package. Once you are done, Winget-Create will validate your manifest to verify that it is correct and allow you to submit your newly-created manifest directly to the winget-pkgs repository by linking your GitHub account. Alternatively, you can use the YamlCreate.ps1 Script. More information on using YamlCreate is found in the script documentation.
If you are authoring a manifest yourself one of the important things to note related to installer types is architecture. In many cases the installer itself may be an x86 installer, but it will actually install the package for the architecture of the system. In these cases, the installer type in the manifest should indicate the architecture of the installed binaries. So in some cases the actual installer itself targets x86, but in fact it will install an x64 version of the package.
You can either download the latest release of Winget-Create from its GitHub repository or use Winget to install it for you by running the following command:
winget install wingetcreate
Now that you have Winget-Create installed onto your machine, you are ready to generate your first manifest by running the New command. To do so, simply run the following command in your terminal:
wingetcreate new <Installer URL(s)>
There are many other commands available in Winget-Create to help you update existing manifests or submit new manifests. Feel free to try it out!
If you decide to create or edit your manifest by manually editing the YAML, it is important to make sure that you are validating your manifest. You can do this by running the validate command from Winget which will tell you if your manifest is valid, or which parts need to be fixed:
winget validate --manifest <Path to manifest>
It is important to test your manifest before submission to ensure it meets the repository's quality standards. While it isn't possible to describe everything that we check for when reviewing contributions, testing your manifest helps keep the quality of contributions high and increases the chance of your contribution being accepted.
- Manifests should be tested to ensure applications can install unattended
- Manifests should be tested to ensure application version matches the Package Version, or that AppsAndFeaturesEntries are included if necessary
- Manifests should be tested to ensure application publisher matches the defaultLocale Publisher, or that AppsAndFeaturesEntries are included if necessary
- Manifests should be tested to ensure application name matches the defaultLocale PackageName, or that AppsAndFeaturesEntries are included if necessary
After enabling the setting for local manifests (winget settings --enable LocalManifestFiles
), manifests can be tested locally with winget install --manifest <path>
.
If your system supports Windows Sandbox, you can also use the SandboxTest.ps1 Script to test the manifest in the Windows Sandbox. This is the preferred method, as it ensures the package doesn't require any dependencies to install.
Most installers write accurate version data to the Windows Registry, but not all. To help with version matching and correllation between the installed application and the manifest in repo, additional AppsAndFeaturesEntries
metadata can be used. These include the PackageFamilyName
, ProductCode
, UpgradeCode
, and InstallerType
. Additional information on how AppsAndFeaturesEntries
affect version matching, package correllation, and sort order can be found below.
Version Matching and Package Correlation is the process by which WinGet attempts to correlate the metadata for an application installed on your machine and match it to a specific package (Package Correlation) and a specific version of that package (Version Matching) which is available in any source. The goal is to accurately determine the currently installed application and its version so that upgrades can be correctly suggested when available (and not suggested when not available). To do this, WinGet relies on data in Windows Registry and the information available from your configured sources.
There are a few typical use cases when AppsAndFeaturesEntries
should be specified in a manifest.
-
The installer does not write a
DisplayVersion
to registry and either of the following are true:- The
DisplayName
contains the version. - The
ProductCode
contains version.
In either of these cases, the respective field is required in every manifest to accurately match the installed package version to an available version from the source.
- The
-
The
PackageVersion
differed from the installer'sDisplayVersion
at any point in the manifest history.In this case,
DisplayVersion
is required in every manifest to prevent version range mapping errors. If the field is left out, users will be caught in an upgrade loop where theAvailable
version shown when runningwinget upgrade
is lower than thePackageVersion
of the latest manifest. -
The
DisplayVersion
the installer writes to the registry is inherently un-ordered or cannot be sorted properly by WinGetThere are many ways that publishers choose to version their software. This leads to some cases where the way WinGet sorts versions will not work properly. Some examples include packages that only use commit hashes for their releases, packages which prefix the version number with a string, or packages using date versioning of DD-MM-YYYY.
When this happens,
PackageVersion
should be set to something which is sortable by WinGet andDisplayVersion
should be set to the value the installer writes to the registry. For more information, see the section on Version Sorting in WinGet -
The
InstallerType
of the installer which writes the registry keys does not match theInstallerType
of the manifestIn some cases an EXE installer may call an embedded MSI which writes data to the registry in a different format. While the
InstallerType
may be correctly identified in the manifest, the WinGet CLI will detect the registry entries as being from an MSI and return an error that the installation technology does not match when runningwinget upgrade
. This requires theInstallerType
to be specified inAppsAndFeaturesEntries
For more information on how to specify AppsAndFeaturesEntries
and what the available metadata fields are, please see the Manifest Specification.
Inherently, all versions are strings. Whether a publisher uses a date code, a commit hash, or some other crazy format they are all saved as string values in the Windows Registry. In fact, a sematic version is just a string with a certain format. To convert these strings into versions and sort them, WinGet goes through the following process.
Important
Step 1 of the below process only occurs in WinGet version 1.9.1763-preview or newer If you are using an older version of WinGet, version preambles may not be handled correctly
- If there is a digit before the first
.
or there is no.
, trim off all leading non-digit characters. Examples:v1.0.1
becomes1.0.1
version 12
becomes12
- Split the string at each
.
, discarding the.
- Create a new
Part
from each of the split sections- A
Part
consists of two components - aninteger
, and astring
- To create a
Part
, whitespace characters are first trimmed from the start and end of the section - Then, numeric characters are parsed from the start of the section and used to create the
integer
. - Once a non-numeric character is encountered, the remainder of the section is considered the
string
- Example: If the section is
2024Mar15
, then2024 → integer
andMar15 → string
- A
- Compare the two parts created from the first section of the
Version
.- If the two parts are not equal, whichever
Part
is larger corresponds to the larger version - See below for an explanation on how parts are compared
- If the two parts are not equal, whichever
- If the two parts are equal, repeat step 3 with each consecutive pair of parts
- If both versions have no more parts, they are equal
- If one version has more parts and the other does not, pad the shorter version with an additional
0
as needed
When comparing one Part
to another, WinGet goes through the following process.
- Compare the two
integer
values- If the two
integer
are not equal, whicheverPart
has the largerinteger
is larger
- If the two
- If the two
integer
are equal, check if there is a value instring
- If both values of
string
are empty, the parts are equal - If one
Part
has a value instring
and the other does not, thePart
which does not have a value instring
is considered to be greater - Example: When comparing
34
and34-beta
, theinteger
is equal for both (34
). However, thestring
for the former is empty and thestring
for the latter is-beta
, so34
is the largerPart
. This leads to1.2.34
being considered a higherVersion
than1.2.34-beta
- If both values of
- If both parts have a value in
string
, perform a case-insensitive comparison of the two- If the values of
string
are not equal, the lexicographic comparison determines whichPart
is larger
- If the values of
Version A | Version B | Comparison Result | Explanation |
---|---|---|---|
1.2.0 | 1.2 | Equal | Version B will be padded with zeros to match the same number of Parts as Version A |
1.2 | 1.2-rc | Version A |
The -rc causes Version B to have a string in the second Part where Version A does not |
1.2.3 | 1.2.4-rc | Version B |
The integer on the third Part is larger for Version B |
v1.2 | 1.1 | Version A |
The leading v will be trimmed off of Version A , and 1.2 is a higher version than 1.1 due to integer comparison in the second Part |
1.2.3a | 1.2.3b | Version B |
b is lexicographically greater than a |