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

feat(updater): Add Channel Support for Github with PreRelease #6505

Merged
merged 13 commits into from
Jan 27, 2022
5 changes: 5 additions & 0 deletions .changeset/github-channel-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"electron-updater": minor
---

feat(updater): Add Channel Support for Github with PreRelease
65 changes: 54 additions & 11 deletions packages/electron-updater/src/providers/GitHubProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export abstract class BaseGitHubProvider<T extends UpdateInfo> extends Provider<
protected computeGithubBasePath(result: string): string {
// https://github.com/electron-userland/electron-builder/issues/1903#issuecomment-320881211
const host = this.options.host
return host != null && host !== "github.com" && host !== "api.github.com" ? `/api/v3${result}` : result
return host !== null && host !== "github.com" && host !== "api.github.com" ? `/api/v3${result}` : result
}
}

Expand All @@ -54,11 +54,38 @@ export class GitHubProvider extends BaseGitHubProvider<GithubUpdateInfo> {
const feed = parseXml(feedXml)
// noinspection TypeScriptValidateJSTypes
let latestRelease = feed.element("entry", false, `No published versions on GitHub`)
let tag: string | null
let tag: string | null = null
try {
if (this.updater.allowPrerelease) {
// noinspection TypeScriptValidateJSTypes
tag = hrefRegExp.exec(latestRelease.element("link").attribute("href"))![1]
const currentChannel = this.updater?.channel || String(semver.prerelease(this.updater.currentVersion)?.[0]) || null
for (const element of feed.getElements("entry")) {
// noinspection TypeScriptValidateJSTypes
const hrefElement = hrefRegExp.exec(element.element("link").attribute("href"))!

// If this is null then something is wrong and skip this release
if (hrefElement === null) continue

// This Release's Tag
const hrefTag = hrefElement[1]
//Get Channel from this release's tag
const hrefChannel = semver.prerelease(hrefTag)?.[0] || null

const shouldFetchVersion = !currentChannel || ["alpha", "beta"].includes(currentChannel)
const isCustomChannel = !["alpha", "beta"].includes(String(hrefChannel))
// Allow moving from alpha to beta but not down
const channelMismatch = currentChannel === "beta" && hrefChannel === "alpha"

if (shouldFetchVersion && !isCustomChannel && !channelMismatch) {
tag = hrefTag
break
}
KenCorma marked this conversation as resolved.
Show resolved Hide resolved

const isNextPreRelease = hrefChannel && hrefChannel === currentChannel
if (isNextPreRelease) {
tag = hrefTag
break
}
}
} else {
tag = await this.getLatestTagName(cancellationToken)
for (const element of feed.getElements("entry")) {
Expand All @@ -77,17 +104,33 @@ export class GitHubProvider extends BaseGitHubProvider<GithubUpdateInfo> {
throw newError(`No published versions on GitHub`, "ERR_UPDATER_NO_PUBLISHED_VERSIONS")
}

const channelFile = getChannelFilename(this.getDefaultChannelName())
const channelFileUrl = newUrlFromBase(this.getBaseDownloadPath(tag, channelFile), this.baseUrl)
const requestOptions = this.createRequestOptions(channelFileUrl)
let rawData: string
let channelFile: string = ""
mmaietta marked this conversation as resolved.
Show resolved Hide resolved
let channelFileUrl: any = ""
const fetchData = async (channelName: string) => {
channelFile = getChannelFilename(channelName)
channelFileUrl = newUrlFromBase(this.getBaseDownloadPath(String(tag), channelFile), this.baseUrl)
const requestOptions = this.createRequestOptions(channelFileUrl)
try {
return (await this.executor.request(requestOptions, cancellationToken))!
} catch (e) {
if (e instanceof HttpError && e.statusCode === 404) {
throw newError(`Cannot find ${channelFile} in the latest release artifacts (${channelFileUrl}): ${e.stack || e.message}`, "ERR_UPDATER_CHANNEL_FILE_NOT_FOUND")
}
throw e
}
}

try {
rawData = (await this.executor.request(requestOptions, cancellationToken))!
const channel = this.updater.allowPrerelease ? this.getCustomChannelName(String(semver.prerelease(tag)?.[0] || "latest")) : this.getDefaultChannelName()
rawData = await fetchData(channel)
} catch (e) {
if (!this.updater.allowPrerelease && e instanceof HttpError && e.statusCode === 404) {
throw newError(`Cannot find ${channelFile} in the latest release artifacts (${channelFileUrl}): ${e.stack || e.message}`, "ERR_UPDATER_CHANNEL_FILE_NOT_FOUND")
if (this.updater.allowPrerelease) {
// Allow fallback to `latest.yml`
rawData = await fetchData(this.getDefaultChannelName())
} else {
throw e
}
throw e
}

const result = parseUpdateInfo(rawData, channelFile, channelFileUrl)
Expand Down