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

New electron-updater #3084

Merged
merged 5 commits into from
Jun 12, 2024
Merged

New electron-updater #3084

merged 5 commits into from
Jun 12, 2024

Conversation

philrz
Copy link
Contributor

@philrz philrz commented Jun 7, 2024

Fixes #3082, which has detailed background on what's being fixed here and what else we expect to gain by moving to a newer electron-updater.

Starting from the code on this branch, I've done an exhaustive set of successful upgrade tests in personal fork repos of Zui and Zui Insiders on both macOS and Ubuntu (.deb). If this PR should get approved, after having updated the branch with any suggestions from reviewers, I'll catch it up with main and repeat the tests one last time including both Windows and Rocky Linux (.rpm) as well for completeness. I happened to skip those on the first pass since in the past I've found update behavior on Windows closely tracks what we see on macOS and likewise between the different Linux installers, so I figured I'd save a little time on the first pass since I assumed I'd want to re-test again after merging suggestions anyway.

Here's a complete run down of all the tests I performed and the results.

  1. Make personal forks of both Zui and Zui Insiders repos per instructions here

    • I manually staged an initial Zui Insiders release based on v1.6.1-33 from the "official" Insiders repo so that way there'd be an existing release to increment from. I then deleted the release and its tag after I made the first proper Insiders release in my fork repo.
    • In the Zui fork, I made the repo name changes from brimdata to philrz in both the main branch and the release/v1.7.0 branch
  2. In the Zui fork, delete the v1.7.0 tag and create a new v1.7.0 release based off the release/v1.7.0 branch

    • This will serve as a baseline similar to our production users running GA Zui v1.7.0 today, which has the old electron-updater
  3. In the Zui Insiders fork, create a new release based off the release/v1.7.0 branch

    • This will serve as a baseline similar to our production users running GA Zui Insiders builds that pre-date the changes in Apple Silicon macOS test/builds #3077
    • Test result: Zui Insiders release v1.7.0 was created
  4. In the Zui Insiders fork, create a new release in my personal repo based off the tip of main

    • This will serve as a baseline similar to our production users running GA Zui Insiders builds in the time since the changes from Apple Silicon macOS test/builds #3077 have merged
    • Test result: Zui Insiders release v1.7.1-0 was created
    • Test result: On my Mac, I installed the Insiders v1.7.0 and it found/auto-updated to v1.7.1-0
    • Test result: On my Linux VM, I installed the Insiders v1.7.0 and it did not initially see the v1.7.1-0 as an eligible update target, but this is due to the known "Problem 1" described in Linux update bugs #3082. Therefore I manually downloaded the Zui---Insiders-1.7.1-0-x64.zip artifact, renamed it to Zui---Insiders-1.7.1-0-mac.zip, and uploaded that to the Release. After waiting about 15 minutes, now the app did find v1.7.1-0 as an eligible update target.
  5. In the Zui fork, advance the version string in package.json to 1.8.0 and merge the new-electron-updater PR

    • This is effectively the same step we'll do before prepping the next GA Zui release.
  6. In the Zui fork, create a new v1.8.0 release

    • Since the older v1.7.0 Linux release still has the "Problem 1" from Linux update bugs #3082, I manually added the Zui-1.8.0-mac.zip to its Release page so Linux users would see this release as an eligible update target
    • Test result: On my Mac, I installed the v1.7.0 release and it auto-updated to v1.8.0
    • Test result: On my Linux VM, I installed the v1.7.0 release and it saw v1.8.0 as an eligible update target
  7. In the Zui Insiders fork, create a new Zui Insiders release

    • Test result: Zui Insiders release v1.8.0 was created. Since the older Insiders releases still have the "Problem 1" from Linux update bugs #3082, I manually added the Zui---Insiders-1.8.0-mac.zip to its Release page so Linux users would see this release as an eligible update target.
    • Test result: On my Mac, I installed the v1.7.0 release and it auto-updated to the v1.8.0 release
    • Test result: On my Mac, I installed the v1.7.1-0 release and it auto-updated to the v1.8.0 release
    • Test result: On my Linux VM, I installed the v1.7.0 release and it saw v1.8.0 as an eligible update target
    • Test result: On my Linux VM, I installed the v1.7.1-0 release and it saw the v1.8.0 release as an eligible update target.
  8. In the Zui Insiders fork, trigger creation of releases -insiders.1, -insiders.12, ... , -insiders.10

    • Test result: On my Mac, I installed v1.7.0 and auto-updated to v1.8.1-insiders.10
    • Test result: On my Mac, I installed v1.7.1-0 and auto-updated to v1.8.1-insiders.10
    • Test result: On my Mac, I installed v1.8.0 and auto-updated to v1.8.1-insiders.10
    • Test result: On my Mac, I installed v1.8.1-insiders.9 it auto-updated to v1.8.1-insiders.10
    • Test: On my Linux VM, I installed v1.7.0 and it found v1.8.0 as the latest available, but of course clicking the Install button brought up the /releases/latest page on GitHub such that I was shown v1.8.1-insiders.10 as the update target
    • Test result: On my Linux VM, I installed v1.7.0 and it found v1.8.0 as the latest available, but of course clicking the Install button brought up the /releases/latest page on GitHub such that I was shown v1.8.1-insiders.10 as the update target
    • Test result: On my Linux VM, I installed v1.7.1-0 and it found v1.8.0 as the latest available, but of course clicking the Install button brought up the /releases/latest page on GitHub such that I was shown v1.8.1-insiders.10 as the update target
    • Test result: On my Linux VM, I installed v1.8.0 and it found v1.8.1-insiders.10 as the latest available (and I'd not had to manually add any "mac ZIP" file for the release)
    • Test result: On my Linux VM, I installed v1.8.1-insiders.9 and it found v1.8.1-insiders.10 as the latest available (and I'd not had to manually add any "mac ZIP" file for the release)
  9. In the Zui fork, create a new v1.9.0 release

    • Test result: On my Mac, I installed the v1.7.0 release and it auto-updated to the v1.9.0 release
    • Test result: On my Mac, I installed the v1.8.0 release and it auto-updated to the v1.9.0 release
    • Test result: On my Linux VM, I installed v1.7.0 and it found v1.8.0 as the latest available, but of course clicking the Install button brought up the brimdata.io Downloads that would offer v1.9.0 as the update target
    • Test result: On my Linux VM, I installed v1.8.0 and it found v1.9.0 as the latest available (and I'd not had to manually add any "mac ZIP" file for the release)

Conclusion: Once users get on to one of the builds running the newer electron-updater, they'll find the proper "latest" release for both Zui and Zui Insiders without any manual intervention on our part. The test results indicate that auto-update users (macOS) will make this transition without any manual intervention on our part. On Linux, we'll need to manually provide the "mac ZIP" file as part of the first releases that have the newer electron-updater, but once they make that leap, their apps will keep finding "latest" releases based on just the presence of the latest-linux.yml that's created automatically by our build process. And since our Linux "helper" just lands them on a "manually download the latest" web page whenever a newer release is detected, they complete this hop easily.

@@ -40,7 +40,7 @@ export class InsidersPackager {
const version =
this.strategy === 'match-stable'
? this.stableVersion
: semver.inc(this.lastVersion, 'prerelease');
: semver.inc(this.lastVersion, 'prerelease', 'insiders');
Copy link
Contributor Author

Choose a reason for hiding this comment

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

During #3082 debug, at one point I'd advanced the electron-updater dependency to the latest (6.2.1) just to see if any of the problems I'd observed had already been fixed. What I found was that Zui Insiders auto-updates actually broke in places like they used to work before, such as macOS.

I debugged further by putting tons of console debug logging in the electron-updater/out/providers/GitHubProvider.js for both our old and the lastest electron-updater versions (GitHubProvider.js.4.3.8.gz and GitHubProvider.js.6.2.1.gz, respectively). What this revealed is that the "channels" support added in electron-updater v5 did not play nice with the way we'd been creating prerelease version strings in Zui Insiders. Specifically, while the lone trailing digits like in v1.7.1-24 are legal per the semver spec and the spec says "Identifiers consisting of only digits are compared numerically", the debug output showed that electron-updater was treating the trailing digits as the "channel name" (i.e., channel name 24 in this case) and so the lack of any further numbers after that channel name (e.g., -24.1, -24.2) meant that once running a Zui Insiders prerelease version the autoUpdater would not see any of the higher-numbered prereleases (e.g., -25, -26, etc.) as eligible update targets.

Thankfully, a solution did reveal itself, and that's to lean into the channel feature. In addition to the "official" supported channel names like alpha and beta, electron-update also supports "custom" channel names, such as I'm doing here, which results in release version strings like v1.7.1-insiders.24. That makes it happy since it finds insiders as the channel name and 24 as a version that testing confirms is treated like a number (e.g., a -insiders.9 release does see an -insiders.10 release as an eligible update target).

We're not currently trying to do anything fancy with channels (e.g., maintain separate alpha and beta channels, let users bounce between channels, downgrade, etc.) and since testing confirms that this one change gets us to what we need I'm keen to make the minimal change for the maximum benefit. Another lemonade-from-lemons effect is that the presence of the explicit insiders in the version string is another nice self-documenting way to know if a user is running Insiders rather than regular Zui, such as if they're pinging us for Support and we ask them to show their version string from About.

@@ -91,7 +91,7 @@
"electron-localshortcut": "^3.2.1",
"electron-log": "5.0.0-beta.6",
"electron-mock-ipc": "^0.3.12",
"electron-updater": "^4.3.8",
"electron-updater": "6.2.1",
Copy link
Contributor Author

@philrz philrz Jun 7, 2024

Choose a reason for hiding this comment

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

Previously we were using the ^ to automatically update to minor/patch electron-updater releases as they became available. I've now spent enough time testing through the release history of electron-updater that I don't wholly trust the stewardship of the project to maintain stability between major releases. We also don't have automated test coverage in this area, which is more risk. Therefore since I've done so many days of testing on this 6.2.1 release I'm keen to lock us in place until we have a specific reason to move to something newer and make the appropriate investment in another round of testing at that time.

Comment on lines +1 to +16
import {autoUpdater} from "electron-updater"
import {Updater} from "./types"
import semver from "semver"
import {app, shell} from "electron"
import env from "src/app/core/env"
import links from "src/app/core/links"
import pkg from "src/electron/pkg"
import {Updater} from "./types"
import {getMainObject} from "src/core/main"

autoUpdater.autoDownload = false
autoUpdater.autoInstallOnAppQuit = false
autoUpdater.forceDevUpdateConfig = true

export class LinuxUpdater implements Updater {
async check() {
const latest = await this.latest()
const {updateInfo} = await autoUpdater.checkForUpdates()
const latest = updateInfo.version
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the big payoff. What I'm adding here plus the code removal in this same file effectively drops our old "Linux update helper" (the one that tried to look for a newer macOS release as a sign that a newer Linux release is surely available as well) and allows us to use the autoUpdater to check for the latest Linux release. This approach became possible when electron-updater added the "beta" support for Linux autoUpdate in electron-userland/electron-builder#7060 (so, it became part of electron-updater v6). This includes the creation of the latest-linux.yml build metadata which is why we can now just call autoUpdater.checkForUpdates() and get a correct answer for "What's the latest Linux release available relative to the one I'm running?" (i.e., it fixes the "Problem 2" described in #3082).

FWIW, I did test out the "beta" support for true Linux autoUpdate and it didn't work for me, complaining of sha512 checksum mismatch between the build itself and its metadata. Since the scope of my testing/changes was already significant enough, plus it's a "beta" feature after all, I chose to not dig further into that for now and instead maintain feature parity with what we already provide on Linux, i.e., check for a newer release and pop up a notification, but clicking Install just brings up the page in the user's browser where they can download the latest.

I recognize that I'm effectively duplicating some code from mac-win-updater.ts here, but since I'm nervous about my JavaScript skills I wanted to minimize the degree to which I was modifying existing code. @jameskerr if you'd like to push a commit to de-duplicate any of what I've done between these two updater files that's fine with me, since I'm planning on doing a final round of testing after getting approval on the PR anyway. Or if you're ok living with some duplication, once I figure out what it'd take to get Linux autoUpdate working (something I'd definitely want to do soon) we should be able to collapse down to a single file of updater code at that time anyway.

@@ -6,6 +6,7 @@ import {getMainObject} from "src/core/main"

autoUpdater.autoDownload = false
autoUpdater.autoInstallOnAppQuit = false
autoUpdater.forceDevUpdateConfig = true
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 previously had not been using it since I always opt to test in personal fork repos, but during my test work I became aware of the apps/zui/dev-app-update.yml file. This allows for quick & dirty update testing in Dev mode since it allows us to fiddle with the current version string in package.json and the owner & repo settings in this YAML file and immediately see how the app would react if it had been bundled/released and was checking for an update at the configured GitHub Releases page. Well, per electron-userland/electron-builder#6863 and the fix in electron-userland/electron-builder#7117, within the jump period between our prior electron-updater version and the latest v6.2.1, they effectively broke it and now require setting this forceDevUpdateConfig in order for the file to be leveraged in Dev mode.

@philrz philrz marked this pull request as ready for review June 7, 2024 19:57
@philrz philrz self-assigned this Jun 7, 2024
@philrz philrz requested a review from jameskerr June 7, 2024 19:58
@philrz
Copy link
Contributor Author

philrz commented Jun 10, 2024

I'll also document for the record that during some of the macOS auto-updates, I've seen crashes similar to the one in the screenshot below, which happened during the auto-update from the Zui Insiders v1.7.0 to v1.7.1-0 in my test fork repo. I just ignored it and the auto-update seemed to complete successfully and the app relaunched automatically into v1.7.1-0. I'm not too concerned because I recall having seen crashes like this during other macOS auto-updates in the past and I'm guessing it's not something we can easily debug or control. However, I've attached the full crash_report.txt if anyone feels like taking a closer look.

image

@philrz
Copy link
Contributor Author

philrz commented Jun 10, 2024

Here's another "full disclosure" finding: In my testing on Rocky Linux, we find that I can't seem to install the RPM for regular Zui while Zui Insiders is already installed. It was on RPM-based Linux that I first found and filed open issue #1588 where the conflict surfaced during an install of a newer Zui when an older Zui was already installed, which led to the guidance in the Zui installation docs to explicitly uninstall first to avoid this problem, so I'm not altogether surprised that the same symptom has surfaced between Zui and Zui Insiders installs. This is unfortunate because we'd like users to be able to have both installed side-by-side, but there may be problems related to the installers that are out of our control. In any case, I'll make note of this in #1588 and perhaps at some point we can find a decent fix or workaround.

image

@philrz
Copy link
Contributor Author

philrz commented Jun 12, 2024

During a final round of upgrade testing to include Windows and Rocky Linux (RPM installer), I ended up bumping into unrelated bug #3089. Once its fix in #3090 was merged and I caught this branch up with main to have the benefit of that fix, I restarted a final testing round from the beginning one more time, and this time it all checked out without hitting any new bugs, so I'm going to merge.

I did have to employ one final trick in the Windows testing. The release/v1.7.0 branch was old enough that it was still dependent on an expired code-signing certificate, so I wasn't able to make proper v1.7.0 releases on Windows in my fork repo from which I could check the ability to see newer Windows releases as eligible for update. Thankfully, however, the dev-app-update.yml approach proved useful here. To simulate running a v1.7.0 Zui release, I checked out the release/v1.7.0 branch and set the dev-app-update.yml to:

owner: philrz
repo: zui
provider: github
updaterCacheDirName: zui-dev-updater

Likewise for Zui Insiders:

owner: philrz
repo: zui-insiders
provider: github
updaterCacheDirName: zui-dev-updater

After doing a yarn && yarn start the app launched and did its check for newer updates and popped up a notification just like the real thing.

@philrz philrz merged commit a9af42a into main Jun 12, 2024
4 checks passed
@philrz philrz deleted the new-electron-updater branch June 12, 2024 17:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Linux update bugs
2 participants