Publishing to winget with MSIX Hero

MSIX Hero is a freeware tool used by administrators and packagers for troubleshooting, analysis and debugging of MSIX packages. One of the latest updates introduced a new functionality – the ability to edit and create YAML manifests – a format accepted by winget package manager.

Winget is the newest approach from Microsoft, which aims to offer a centralized, format-agnostic package manager. While it differs substantially from what Linux/UNIX package managers and even Chocolatey, Scoop etc. offer, there seems to be rather a positive reception by the community. Once some missing features are there, together with constantly growing number of apps available, it may eventually become a really interesting part of the ecosystem, possibly one of the first thing the user would install to get his beloved apps and stuff on his newly staged computer.

In this blog post, I will show how to get started, create and validate an app definition and finally push it to the repository. Some basic knowledge of git would help you to get started (as the publishing process relies heavily on a proper git-based workflow), but this guide has been written for git beginners in mind. Just make sure you have a free GitHub account – register for a new one if you do not have any yet.

This tutorial is specifically addressed to those, who may not be quite proficient with git and related stuff, but want to still be able to publish submissions to winget. Users working with git on daily basis can certainly skip large parts of sections, describing how to fork and sync repositories.

Preparing

The app that I am going to publish will be the newest version 1.0.5 of MSIX Hero. The app is going to be an update of a previous version which is already in winget, but every submission is more or less following the same steps, regardless of being a completely new app, or just an updated version.

The first step is to prepare the sources. The app must be installable silently (with or without command line switches) and redistributable as a single file. The format itself is less important, most popular choices are:

  • MSI (Windows Installer) (note: because the file must be completely standalone, make sure that all your files and CAB archives are compressed inside the MSI container)
  • EXE (any format would work, some typical would be setups created by InnoSetup or NSIS).
  • MSIX/APPX (preferred choice for the modern deployment).

MSIX Hero is an MSIX app. The steps for other types are mostly the same.

Validating

Before publishing a new app or a submission, make sure to check if there is no other pending or already accepted submission with the app you want to publish. This will be probably rare in case of less popular, self-developed apps, but may happen otherwise. To ensure there are no conflicts, go to the official Github repository and make sure the publisher / product combination is not available in the following folder:

https://github.com/microsoft/winget-pkgs/tree/master/manifests

In my case, there is already a folder for the publisher/product (MarcinOtorowski/MSIXHero), so I am just going to check its content:

Winget repository

Great, the version 1.0.5 is not there. Obviously, the same applies if the publisher or the product is not yet there. You should also make sure that there are no pending changes. Pending changes are represented by pull requests, visible here:

https://github.com/microsoft/winget-pkgs/pulls

There is a built-in search to make this task a bit easier.

MSIX Hero 1.0.5 is not in the repository, and there is no other pending change (pull request), so we are good to go.

Note: from now on, whenever the name upstream or the original repository is used, the repository microsoft/winget-pkgs is meant by this.

Uploading the setup

The installer must be available online. A web server, or a static file on AWS/Azure would obviously do the trick. Ideally, the link should be permanent, for example if your setup is called setup.exe, then make sure that you include the version or any other identification as a part of the URL, for example:

  • https://your-server.com/download/1.0.2/setup.exe
  • https://your-server.com/download/setup-1.0.2.exe

On the other hand, the following are not the best idea:

  • https://your-server.com/download/setup.exe
  • https://your-server.com/accept-eula.html

Failing to provide a link which is permanent and not changed between versions may have serious consequences, and in worst case prevent the package from being published.

Another important point is that the file must be immediately downloadable, no proxy page, EULA acceptance or CAPTCHA tests are allowed.

Make sure to remember the full URL address of your app and double check that – when entered in the browser address bar – the download starts.

Preparing git environment

Direct pushes to the official repository are not allowed, and everything must be done via so-called “pull requests”. In order to be able to make them, we need to first fork the original repository. In order to do it, go to its root page and press the button Fork in the top-right toolbar:

The button to create a fork.

This will create a fork in your GitHub.

Forked repository

Note: The name fork or remote repository will be used to denote your repository that was based on the Microsoft’s one.

The default branch is set to master. Now, open this forked repository and press the button Code to reveal the options for getting the clone of it on a local computer.

Code > Clone menu

For a relatively easy start, you can use the GitHub Desktop client, or copy the HTTP address to execute a command like:

git clone <url-of-repo> <local-folder>

git is not part of standard Windows installation. If the name cannot be resolved, make sure to install Git for Windows: https://git-scm.com/download/win

In this blog post, I am going to clone my forked repository to a local folder c:\Repos\winget-pkgs

The full command will be:

git clone "https://github.com/marcinotorowski/winget-pkgs.git" "c:\Repos\winget-pkgs"

Whichever option/git client you choose, you should be left with the full copy of the original winget repository. Now, execute another command to create a branch and switch to it (checkout). Branch is a kind-of non-linear, separated encapsulation of your changes. You can name the branch however you like, but as a good practice is should tell what kind of work it contains. In my case, I am going to create a branch called msix-hero-1.0.5 which is pretty self-explaining.

Note: Creating a new branch is not really required, but in my opinion it makes it easier to work and maintain. Moreover, it makes it much easier to work with several concurrent pull request for different apps. Anyway, you could follow the next steps even if you skip creation of the branch.

git branch msix-hero-1.0.5
git checkout msix-hero-1.0.5

Now we should be ready to start with the actual app.

Preparing folder structure

All packages must follow the following naming guidelines:

<root>\manifests\<Publisher>\<ProductName>\<Version>.yaml

It is up to you how you define the names, just make sure they follow more-or-less the same conventions as the other apps in the repository, and just be consequent. In my case, there is already the publisher MarcinOtorowski which contains a folder for MSIXHero, so the only thing left to me is to create a file for the version 1.0.5.0 I am going to publish. Ideally, the names for the publisher and for the product folder should correspond to the package ID that you will define in next steps.

Before going further, make sure the folder for the publisher and its subfolder with the product is there.

These folders do not have to be the same as display name of your publisher or app name – these properties are defined elsewhere. Instead, they should be considered as “technical”, so avoid spaces and non-ASCII characters to keep the folder structure simple and accessible by non-English users.

Given all previous steps, my folder for the application looks like this:

Initial folder structure

Obviously, I could now take some previous definition file and just edit the values that have changed (as a matter of fact, MSIX Hero can open existing YAML files). In this tutorial, I am going to show how to create the definition from scratch.

Creating YAML file with MSIX Hero

MSIX Hero has a graphical UI which makes the creation of the definition pretty easy. Get it from https://msixhero.net if you do not have the program yet.

After starting it, select Tools ribbon, and press Winget manifest (YAML) button.

MSIX Hero ribbon interface > Winget manifest (YAML)

A blank dialog will be shown:

YAML editor (tab Identity)

Identity

Press Load data from MSI/MSIX/EXE… and select the setup file or MSIX package you prepared in one of the first steps. After accepting it, several fields will be automatically filled out (depending on how much information can be read from the setup file):

YAML editor (tab Identity)

Adjust the information as required. Take into account that the package name and the package publisher are display names and will be visible to end-users who later install and browse packages using winget. Package identifier is created automatically based on the details you entered, you may also decide to adjust it to make sure it contains just plain ASCII characters. This ID will be also visible to the end-users. The ID must follow the pattern <PublisherFolderName>.<ProductFolderName> (so essentially the same names that were used for the folder names, but separated by a dot instead of the backslash character).

Metadata

Now go to the second tab. Some of these information will be already provided, the other may be required to enter manually:

YAML editor (tab Metadata)

Most of these are self-explaining. If you have no idea, leave 10.0.0.0 as the minimum required version. You can also provide the value for AppMoniker, which is more or less an alias, which some people are likely to look for. In my case, MSIX Hero has a space in its name, and the main executable name is called msixhero.exe, so I decided to choose msixhero as the AppMoniker.

You can also provide tags, separated by commas, a description and a home page link. All of these meta properties are optional, but still recommended.

Downloads

In the next tab, we need to provide two important required values:

  1. The URL for download (see one of the previous points)
  2. The checksum used to validate the installer

Just enter the URL of your setup into the first field. You have now two choices of how to proceed with a checksum:

  • Calculate it from the downloaded file, or…
  • …calculate if from the local file.

It is recommended to use the first one, as it also makes sure that the file is downloadable and that the checksum is fine. You will get errors later on after sending the submission if the checksum is invalid or the file is not downloadable, so why not to use this chance to make a double check?

After pressing Get hash from installer URL, the file will be downloaded and its checksum will be automatically entered in the Installer hash field:

YAML editor (tab Downloads)

Installer

The content of the next tab may be slightly different depending on the type of the setup. MSIX Hero recognizes several executables, MSI and MSIX packages and may already have some right values for you.

For MSIX packages, you will be asked to provide the hash for the signature. Again, you can do it from a local file or from a remote source, the latter being recommended. Note: The signature hash – as opposed to the installer hash – is not required.

YAML editor (tab Installer)

For other types, you may be asked for some more details. For example, if selecting a generic executable (not NSIS or InnoSetup), three extra fields are provided, and you should at least enter the silent parameters for the installation, otherwise your package may be rejected if it does not install silently:

YAML editor (tab Installer - EXE)

By the way, if your setup has been packaged by InnoSetup or NSIS, MSIX Hero will recognize it and pre-select the correct value. In this case, you do not have to provide a silent command line parameter, because these values are standard for all NSIS/InnoSetup packages.

License + copyright

Finally, the last tabs contain some last missing bits:

YAML editor (tab License + copryight)

Note that in order to get your package accepted, you need to provide the copyright or license information. EULA is not required, but recommended.

Once everything is ready, press Create winget manifest button, and select the location. You should save your file in the folder that we created for publisher/product, and use the version as the file name:

Saving YAML file in the repository

This will ensure, that a file 1.0.5.0.yaml is created in the MarcinOtorowski/MSIXHero folder.

Your package will be automatically pre-validated, and if all values are correct the following message will be shown:

Save confirmation

If the validation did not succeed, make sure to fix the problems and save the file again.

The content of YAML file will look like this:

Id: MarcinOtorowski.MSIXHero
Version: 1.0.5.0
Name: MSIX Hero
Publisher: Marcin Otorowski
License: Copyright (c) 2020, Marcin Otorowski
LicenseUrl: https://msixhero.net/license/
AppMoniker: msixhero
Tags: MSIX, PSF, APPX
Description: The ultimate MSIX toolkit for IT Pros
Homepage: https://msixhero.net/
Installers:
- Arch: x64
  Url: https://msixhero.net/msix-hero-1.0.5.0.msix
  Sha256: 070FA65A9F8B500F0B268960029479B2255F7F4094DDC3A7102E2C8C83D3BD57
  SignatureSha256: D9B3548C22F417B8F5714D58CACC4C4B688E79717E5FCDE21C40178D69141C10
  InstallerType: msix
  Scope: user
MinOSVersion: 10.0.0.0
# Edited with MSIX Hero

Preparing for a pull request

Now we are going to use git to prepare everything for a pull request. We are already in the right branch, so the only thing to be done is to commit the new file and push it our forked repository (origin).

In the repository folder, execute the following command:

git add .

This will stage the only file that we added. Now commit it using the following command:

git commit -m "Add MarcinOtorowski.MSIXHero v1.0.5.0"

The commit message is not really important, but since it is going to be part of the official repository make sure that it is short and descriptive about the changes you intend to push. Use the suggestion above

Now push the changes to the origin (our forked repository) by invoking the following:

git push --set-upstream origin msix-hero-1.0.5

where msix-hero-1.0.5 is just the name of your branch you created.

We are done with the local git repository. Go back to your GitHub (forked repository) and verify that the file is now there:

YAML file available in the forked repository

Note: You must switch the branch to the one that you created (drop-down menu in the top left corner). The default branch master will not have your change yet.

Final validation

MSIX Hero has done already pretty a lot, including the validation. You may still do a double check before making a pull request – verify all names, sources, directory structures etc. You can also use the command

winget validate <path-to-yaml>

to ensure that the YAML is correct.

Don’t be afraid of messing up the repository. As long as you followed these steps you should be on a good way to get your submission accepted. And even if something does not quite work, after making a pull request there is going to be another series of automated checks, which will catch all errors and mistakes. Finally, there is going to be a review, and you will most likely get a feedback from a human that will guide you to the points which may require attention.

Pull request

Now we are going to signal to Microsoft that our package is ready to be submitted and be reviewed. Go to the forked repository, and press Pull request in the top right corner.

Button to create a pull request

You should get something like this:

Pull request summary

Use the description as a checklist, you can remove it before creating a pull request. Most of the points are about the validation which we have already done by either MSIX Hero or winget. However, make sure that you fulfill the first point from the list – in case you haven’t signed the CLA (Contributor License Agreement) visit the link, and follow the steps to complete it automatically. Get back to the pull request dialog after it.

The title of the pull request may stay like your commit message – short and clear. Adjust the description or leave it empty, and press Create pull request. Once done, go to the original repository and locate your pull request in the Pull requests tab:

Pull request item

Click it to get more details:

Pull request details, Azure automation messages etc.

Initially, your submission will be open, and is going to be checked by automated pipelines in Azure. This may take a few minutes, and the content of the page will be refreshed automatically to reflect the changes. After a series of checks, the submission will be tagged and will have to wait for the approval of the assigned person. From my experience, this may take from a few hours to a few days.

Once the validation is complete and your submission is accepted, your product will be available in the official repository, and the commit that you pushed will be a part of the official winget repository.

And if something didn’t work?

Your submission was rejected? There are some typical reasons:

  • Download URL not accessible or missing
  • Mismatch or missing file hash
  • Wrong naming conventions
  • Missing required values in YAML file
  • Invalid values

Make sure to fix them up, according to the guidelines from automated bot and/or from the reviewer. In order to fix and trigger another round of checks, implement the changes locally in your local git repository (the same branch as specified in the pull request). Then, stage and commit the changes, and push the new commit to the origin (see previous steps). Once a change is pushed, the pull request will be updated and the automated verification will start again – you do not have to open new pull request. Hopefully the things will work better this time!

Everything worked!

Congratulations, your package is in winget. Within next hours every user accessing winget CLI will be able to download your newest version. There are some optional steps you can do to clean-up your git workspace, again the following is just a suggestion and there are many other ways:

  1. Remove the branch you created (locally and in the origin (forked) repository)
  2. Update the forked repository from the upstream (original repository) so that both had the same head.
  3. Update the local repository (pull) from the origin/upstream.

This way you are ready to go for the next updates and next submissions.

Summary

Publishing in winget is not difficult, as long as you do a proper validation and remember about a few rules how to work with this Microsoft repo. The creation or editing of manifests is pretty simple if you use MSIX Hero, which can detect setup types, calculate hashes and perform various validation checks.

In terms of publishing, working with git on daily basis helps a lot, but even people with just minimal experience can publish their apps without doing any deeper dive with git and its complex concepts.

I hope you liked this a bit-lengthy tutorial. Leave comments in case of questions or feedback.

By the way: this guideline shows exactly how I update MSIX Hero in winget once a new version comes.

Links and further reading

Leave a Reply