Promote an understanding of how Foundry installs and updates Packages with suggestions for how to create a safe workflow whereby package authors can rest easy knowing that users are at no risk of installing non-working code.
Foundry's package installation and update process is robust enough to allow automatic update detection and installation, while also allowing users who wish to to install a specific version of a package.
Setting up a package to make full use of this ability requires a little legwork, but for modules with frequent updates, the rewards are peace of mind.
Foundry prides itself on the ability to allow users the freedom to install packages from any source, not just the official list. So it's important to understand exactly how Foundry's client installs packages and checks for updates.
Installation is fairly straightforward and can be done in one of two ways.
foundryvtt.com/admin
page and looks for a download
url within it.download
url and checks if it is a zip file. If so, it unzips.download
url from it.download
url and checks if it is a zip file. If so, it unzips.This process has changed as of 0.8.2 with the introduction of "Sidegrading"
version
strings of the installed module's manifest against the fetched manifest.isNewerVersion
helper function to compare manifest version strings.download
and checks if it is a zip file. If so, it unzips.manifest
field has changed in the Package Repository listingmanifest
is overwritten with the new value from the Package Repositoryversion
strings of the installed module's manifest against the fetched manifest.isNewerVersion
helper function to compare manifest version strings.download
and checks if it is a zip file. If so, it unzips.Manifest Field | Action Taken |
---|---|
title | Overwritten with Remote Manifest Value |
description | Overwritten with Remote Manifest Value |
author | Overwritten with Remote Manifest Value |
authors | Overwritten with Remote Manifest Value |
url | Overwritten with Remote Manifest Value |
license | Overwritten with Remote Manifest Value |
readme | Overwritten with Remote Manifest Value |
bugs | Overwritten with Remote Manifest Value |
changelog | Overwritten with Remote Manifest Value |
system | Overwritten with Remote Manifest Value |
download | Overwritten with Remote Manifest Value |
manifest | If Package Repository value changed, prompt user to pick a version. If Remote changed, overwrite |
minimumCoreVersion | Overwritten with minimum value of Remote and Package Repository |
compatibleCoreVersion | Overwritten with maximum value of Remote and Package Repository |
After your submitted package is approved, you'll get access to a Package Management site at foundryvtt.com/admin. From here you can find a list of all of your approved packages. You can use this screen to manage other aspects of the how your Packages are displayed on the Official package list, but we're most concerned about the Versions for this guide.
If a package has no Package Versions present, it will not be available on either the official package list or in the Foundry UI.
This list does not participate in the process of updating a package.
Deleting the latest version from this list will prevent new installations from the UI from installing, but will not prevent updates if the manifest url points to a json with a later version.
See the How Foundry checks for Package Updates section for more information.
This section directly populates the list of released versions on the foundryvtt.com page for your module. It also informs the package installation UI within Foundry which version to download.
There is no limit to how many package versions you can have. Or if there is a limit, it's very high. We can leverage this to allow users to backtrack and install a previous version. This also allows us to "un-release" a version if it turns out there's problems with it.
Figure 1: Example of how these fields display at the bottom of a module's page.
If this increments but the linked manifest json's
version
field has not incremented, automatic updates will not pick up the change.
Should match the version number of the linked module.json
.
Url to the module.json
for this particular release.
This module.json
should have a download
field that points at a zip
of just this release. This is important as it allows a user to go back and download/install a specific version of the module from the history.
A nice-to-have url which points to a release note for this particular release. It could link to a specific heading of a larger release notes file, or to a release-specific page.
It's common to include a changelog in the repository's README or to use your source control host's release feature for this.
This informs the Foundry Package Installer UI which version of the module to offer based on the Core version being used.
Example: A package has two versions, one with the "Required Core Version" of
0.7.4
and one with0.6.6
. A Foundry user looking for this package on a0.6.6
version of foundry will be served the manifest url which satisfies this requirement.
Should match the minimumCoreVersion
field in the linked module.json
.
The minimum required Foundry Core version that this particular release requires to work.
Should match the compatibleCoreVersion
field in the linked module.json
.
The maximum Foundry Core version you are confident to say that this package works in. Note that nothing stops a user from installing the package on a version of Foundry Core that is higher than this.
The files in the package zip that is downloaded and installed on the user's Foundry instance.
download
This field should be a url to only this package version's zip download. It should not point to a place where a user can find the latest version of the package.
manifest
This field should be a stable url that will always point to the latest manifest JSON without needing to change.
Fields for a given row on the Package Admin "Package Version" list.
This should point to this specific version's manifest JSON. The reason for this is because only that specific manifest JSON has the download
field pointing to that particular version's zip files.
Keep this up to date at all times, especially when breaking changes happen.
The odds are good that whatever service you use to host your project repository has some tools that can help keep distinct versions of your package.
Releases are Tags on Github that have extra metadata you can edit from the UI or from an API. Github provides a stable URL that will always point to the latest release: user/repo/releases/latest
.
When a package author is ready to create a release version of their package, they can create a release to tag a particular commit in the history as that version's source. Then they can attach two artifacts to the release:
module.json
-> download
should point at the package.zip
uploaded to this releasepackage.zip
-> this should include the same module.json
as is attachedFrom there, in the Foundry Admin Package Version list, provide the url for the release's manifest as the Manifest URL.
See the full documentation for more information.
There is a lot of cool stuff you can leverage Github Actions to automate with this process. Below are a few repositories to give you some ideas.
module.json
version/download fields, zips up the files, and attaches them to the release./dist
directory and attaches both it and the module.json
to the created release.v*
in the name is pushed which builds and zips the system files, creates a release with that tag's name, and attaches the built files to the release.ElfFriend-DnD is a package author who is ready to release verson 2.23.1 of their module: "AmazingModule".
Their module.json
already leverages the releases/latest
Github Repo url to ensure Foundry clients always look for the most recently released module.json
:
"manifest": "https://github.com/ElfFriend-DnD/AmazingModule/releases/latest/download/module.json"
module.json
:version
increment to 2.23.1download
-> https://github.com/ElfFriend-DnD/AmazingModule/releases/download/2.23.1/module.zip
module.zip
.module.json
changes to keep your repo up to date with the latest version numbers.module.json
and module.zip
files to the release2.23.1
https://github.com/ElfFriend-DnD/AmazingModule/releases/download/2.23.1/module.json
https://github.com/ElfFriend-DnD/AmazingModule/releases/tag/2.23.1
GitLab releases work a lot like the Github releases; they associate a git tag with some additional data. GitLab releases unfortunately do not allow file upload, so you cannot use GitLab releases alone to host a manually uploaded manifest or zip file.
See the Gitlab Releases Docs for more information.
Gitlab CI/CD jobs can be as simple as creating a zip file, to something more complex like compilation (e.g. TypeScript or Babel.js), dynamic module.json
, downloading and bundling dependencies, etc. Files created with GitLab CI/CD can be automatically archived to distribute your module.
Read more in the GitLab CI/CD documentation.