Repository navigation
Releasing
For maintainers. Every release is built by GitHub Actions from this repository.
- Raise
__version__inhoard/__init__.py, and add a## <version>section at the top ofCHANGELOG.md. That section becomes the release's notes, and the build refuses a version without one. The Flatpak's metainfo lists the version by itself: its build adds it to the top of<releases>(scripts/flatpak_metainfo.py, with the section's first sentence as its summary), so there's no need to edit that file. - Merge to
main, and wait for Check to pass. - In Actions, open Release, choose Run workflow on
main, and enter the tag, with itsv(v2.8.0). If the tag doesn't exist yet, the workflow makes it onmain's latest commit, after checking it matches__version__. Pushing the tag yourself does the same.
The Release workflow then:
- builds the source zip and its checksums, signs its build provenance, and makes the release as a draft;
- builds the Windows app (PyInstaller), runs its self-test, builds the installer (Inno Setup), and attaches the installer, the Windows zip and their checksums;
- builds the Mac app twice, on an Apple Silicon and an Intel runner (PyInstaller, then
Hoard.appin a.pkgbyscripts/build_macos_pkg.sh), runs its self-test, and attachesHoard-<version>-macos-apple-silicon.pkgandHoard-<version>-macos-intel.pkgwith their checksums; - builds the Flatpak (flatpak-builder, in Flathub's GNOME 51 container; its build checks Hoard's window support
and runs the self-test in the sandbox), and attaches
Hoard-<version>-linux-x86_64.flatpakandSHA256SUMS-linux.txt; - has VirusTotal scan every file people download (
scripts/scan_release_virustotal.py), and adds each file's result and report link to the release notes; - publishes the release, once every file is on it and none was flagged.
Every file has signed build provenance (gh attestation verify). The Windows programs and installer are
code-signed (see Code signing (Windows) below); the Mac packages aren't signed or notarized by Apple: see
Installing Hoard for what users see.
A beta is a release of the next version before it's finished, for testers, from this same repository. Tag it
v<version>-beta.<n>: v3.1.0-beta.1, then v3.1.0-beta.2, and v3.1.0 when it's done.
- Set
__version__ = "3.1.0-beta.1", and add a## 3.1.0-beta.1section toCHANGELOG.md(the beta's notes on GitHub; the website's What's new page leaves beta sections out). The Flatpak's build lists it in the metainfo as a development release by itself. - Run Release with the tag
v3.1.0-beta.1, as above. The release is titled Hoard 3.1.0 beta 1 and published as a pre-release, which never becomes Latest, so the website's download buttons, and everyone else's update checks, stay on the last release. - Testers turn on Get beta updates (Settings, under Updates). Hoard then offers each newer beta, and the
finished
3.1.0when it's out. The Windows app installs a beta itself, as it does a release.
When 3.1.0 is ready, fold the beta sections of CHANGELOG.md into one ## 3.1.0 and release it as usual.
The Windows and Mac builds take numbers-only versions for the parts of the system that need them (a beta
3.1.0-beta.1 is 3.1.0 there); the file names and Hoard itself say the whole version.
Every kind of release shares this repository's Releases page, told apart by its tag and title
(scripts/release_info.py):
| Tag | Title | Status |
|---|---|---|
v3.1.0 |
Hoard 3.1.0 | a release, and Latest |
v3.1.0-beta.2 |
Hoard 3.1.0 beta 2 | a pre-release |
unity-v0.6.0 |
Hoard for Unity 0.6.0 | a release, never Latest |
unity-v0.6.0-beta.1 |
Hoard for Unity 0.6.0 beta 1 | a pre-release |
Latest always stays on the newest release of the app: the website's download buttons and the README's badge
follow it. The release workflows set all of this themselves. To bring older releases in line (titles, pre-release
status, Latest), run Actions › Tidy releases › Run workflow: unticked, it only lists what it would change in
the run's log; ticked, it changes it. It never touches a release's files, notes or tag. (It's
scripts/tidy_releases.py: on your own computer, run it as it is to see the changes, and with --apply and
GH_TOKEN set, from gh auth token, to make them.)
This repository has immutable releases turned on: once a release is published, no file can be added to it or changed, and its tag can never be used for another release, even after deleting the release. (Its title, notes and pre-release status can still be edited.) That's why the release stays a draft until every file is attached.
-
A build failed? The run cleans up after itself: it deletes the draft (never published), and the tag too
when the run made it. Fix the problem on
main, then run the workflow again with the same tag. (A tag you pushed yourself is left for you to delete, under Code › Tags, or release the next version.) To re-run only the failed jobs instead, tick If a build fails, keep its draft and tag when you start the run. The workflow also checks the Flatpak's metainfo before building anything, so a broken one stops it at once. -
VirusTotal flagged a file? The release stays a draft, and its notes list each file's result with a link to
VirusTotal's report. Unsigned apps built with PyInstaller are sometimes flagged by one or two engines by
mistake. Open the report: if it's a false positive (a generic or heuristic name, from an engine or two), run the
workflow again for the tag with Publish even if VirusTotal flags a file ticked; it scans again, notes that
it was checked by hand, and publishes. If it looks real, don't publish: find out why first. Report a false
positive to the engine's maker, which clears it: Windows won't let a browser download a file Microsoft's engine
flags, so the run keeps the flagged files under Artifacts (
virustotal-flagged-files), in a zip with the passwordinfected. Upload that zip as it is (for Microsoft, at microsoft.com/wdsi/filesubmission, as a software developer), and give the password where it asks.
Once, when setting the repository up: make a free account at virustotal.com, copy
the API key from your profile, and add it as the repository secret VT_API_KEY (Settings › Secrets and
variables › Actions › New repository secret). Without it the release stays a draft, saying so.
The scan uses VirusTotal's public API (4 requests a minute, 500 a day): a file VirusTotal already knows is only
looked up, and new ones are all uploaded, then their scans waited for together, so a release takes about 10 to 20
minutes more. The log says what it's doing as it goes (Waiting for VirusTotal (6 min so far): … queued): a busy
day's queue can be slow, so leave it running. It waits up to 40 minutes; if VirusTotal still hasn't finished, the
job fails saying which files, and Re-run failed jobs later picks up the finished scans without sending anything
again. Only the
scan step sees the key. Files sent to VirusTotal are shared with its security partners, as with any upload there;
they're the same files the release makes public.
- Published something broken? Don't delete it expecting to reuse the version. Raise the version and release again (2.4.0 was re-released as 2.4.1 this way).
Hoard.exe, hoard-cli.exe and the setup are signed with Azure Artifact Signing (Microsoft's Trusted
Signing), so Windows and Defender know they're Hoard's. Signing happens in the release's Windows job, only where
it's set up: a fork, or this repository before it's set up, builds unsigned, as before. The setup's uninstaller
isn't signed yet.
Once, when setting it up (an Azure subscription with a payment method; the Basic plan is about $10 a month):
-
In the Azure portal, create an Artifact Signing account (search "Artifact Signing" or "Trusted Signing"), in a region near you, on the Basic plan. Note its name and its endpoint (on its Overview, such as
https://eus.codesigning.azure.net/). -
In the account, under Identity validations, start a Public validation for yourself as an individual, and finish Microsoft's identity check. It can take a few days. (Before you can, you may need to give your own Azure user the Artifact Signing Identity Verifier role on the account, under Access control (IAM).)
-
Once validated, under Certificate profiles, create a Public Trust profile using that validation, and note its name.
-
Let GitHub sign in without a password: in Microsoft Entra ID › App registrations, register an app (say "Hoard release signing"). In it, under Certificates & secrets › Federated credentials, add one for GitHub Actions deploying Azure resources: organisation
Soloflighter1010, repositoryHoard-Asset-Manager, entity Environment, environmentrelease-signing. -
On the signing account, under Access control (IAM), give that app the Artifact Signing Certificate Profile Signer role.
-
In this repository, under Settings › Environments, open (or create)
release-signing, and add:- secrets
AZURE_CLIENT_ID(the app's Application (client) ID),AZURE_TENANT_ID(its Directory (tenant) ID) andAZURE_SUBSCRIPTION_ID(your subscription's ID); - variables
AZURE_SIGNING_ENDPOINT,AZURE_SIGNING_ACCOUNTandAZURE_SIGNING_PROFILE(from steps 1 and 3).
Optionally, under the environment's Deployment branches and tags, allow only
mainand tagsv*. - secrets
The next release is signed. Its Windows job checks each signature as Windows sees it, and fails if one isn't valid. Reputation with SmartScreen and Defender builds over the first few signed releases.
Like requirements-app.txt for Windows, requirements-mac.txt and requirements-flatpak.txt are locked with
hashes, and made from their .in files by the uv pip compile command at the top of each. They're constrained
to requirements.txt and requirements-app.txt, so every Hoard runs the same versions (a test checks). The
Flatpak builds offline, so after regenerating requirements-flatpak.txt, run python scripts/flatpak_deps.py
to rewrite packaging/flatpak/python3-deps.json (each file's address and hash).
packaging/flatpak/io.github.soloflighter1010.Hoard.yml is written to Flathub's rules (a stable runtime, every
source pinned by hash, a narrow sandbox, AppStream metainfo), so it can be submitted there. A Flathub submission
lives in its own repository, with the manifest's hoard source changed from this folder to a git source at
the release's tag and commit.
- Raise
versioninPackages/soloflighter.hoard/package.json, and add a## <version>section toPackages/soloflighter.hoard/CHANGELOG.md. - Merge to
main. - In Actions, open Build Release and choose Run workflow. It tests the package's core, builds the
.zip,.unitypackageandpackage.jsonand makes the release as a draft, has VirusTotal scan the.zipand.unitypackage(adding each result to the notes, as for the app), then publishes it, taggingunity-v<version>. If VirusTotal flags a file, the release stays a draft: check the reports as for the app (see VirusTotal flagged a file? above), then run Build Release again with Publish even if VirusTotal flags a file ticked. - Build Repo Listing runs after it, rebuilding the VCC listing from every release and publishing it to GitHub Pages (https://hoard.furryup.link/index.json, the website's own address: the github.io one only forwards there).
Once, when setting the repository up: add the repository variable PACKAGE_NAME = soloflighter.hoard
(Settings › Secrets and variables › Actions › Variables), and set Settings › Pages › Source to GitHub
Actions. Pages only deploys from main, so a listing build started by a release event is re-run on main.
Hoard's website (https://hoard.furryup.link/, its own address for GitHub Pages) is the site/ folder, deployed by
Build Repo Listing with the VCC listing: the site at the root, VRChat's listing page at vcc/, and
index.json (and the older vpm/index.json) where VCC finds them. A change to site/ reaching main deploys
it. It loads nothing from other sites (a test checks); its download buttons ask GitHub's API for the latest
release's files, and open the releases page without it. Its fonts are the app's, cut down to Latin characters
with pyftsubset (fontTools), and its screenshot is of the app with a sample library.
Its What's new page (changelog.html) is built from CHANGELOG.md on each deploy
(scripts/build_site_changelog.py), with each release's date from GitHub, so a change to the changelog reaching
main updates it; nothing generated is kept in the repository. Testers (site/testers.html) thanks the people
who test releases: add a name there, one <li> each.
The wiki is written in the repository's wiki/ folder and reviewed like code. When a change to wiki/ reaches
main, the Wiki workflow publishes it, replacing every page, so edit the pages there, not on GitHub.
Once, before the first publish: open the repository's Wiki tab and save any first page. GitHub only creates the wiki's storage when its first page is saved; the workflow then replaces it.
Check runs for every pull request and every push to main: the tests on Ubuntu and Windows (browser tests
included, and the Unity core on Ubuntu), the release zips, the Unity package, the Windows app with its
self-test, the Mac app (Apple Silicon) with its self-test and .pkg, and the Flatpak. See Development.
Repository ·
Releases ·
Report a problem ·
Report a security problem ·
MIT license. This wiki is written in the repository's wiki/ folder: suggest changes there.