Give beta builds versions from the future

Related: #714
This commit is contained in:
Oliver Blanthorn 2026-07-24 16:22:57 +02:00
parent 8bd4144ff7
commit 9890b0a1bd
No known key found for this signature in database
GPG key ID: 2BB8C36BB504BFF3
6 changed files with 54 additions and 32 deletions

View file

@ -349,6 +349,8 @@ If you want to build a signed copy (e.g. for the non-developer release), you can
You can build unsigned copies with `scripts/sign nosign{stable,beta}`. NB: The `stable` versus `beta` part of the argument tells our build process which extension ID to use (and therefore which settings to use). If you want a stable build, make sure you are on the latest tag, i.e. `git checkout $(git tag | grep '^[0-9]\+\.[0-9]\+\.[0-9]\+$' | sort -t. -k 1,1n -k 2,2n -k 3,3n | tail -1)`.
Maintainers create the next release after fetching tags with `scripts/version.js next {0,1,2} [release name]` and committing the changed manifest. Beta builds use that version while retaining the release name in their displayed version. Once its changelog entry is ready, `scripts/version.js release` dates the entry, commits it, and tags the version already in `src/manifest.json`.
If you are on a distribution which builds Firefox with `--with-unsigned-addon-scopes=` set to `app` and/or `system` (which is most of them by users: Arch, Debian, Ubuntu), you can install your unsigned copy of Tridactyl with `scripts/install.sh [directory]`. If you're on Arch, the correct directory is probably selected by default; on other distributions you might have to go hunting, but it probably looks like `/usr/lib/firefox/browser/extensions`.
### Building on Windows

View file

@ -18,6 +18,16 @@ function release_name(manifest) {
.trim()
}
function validate_release_version(manifest) {
if (!/^\d+\.\d+\.\d+$/.test(manifest.version) || manifest.version_name !== [manifest.version, release_name(manifest)].filter(Boolean).join(" ")) {
throw new Error("Manifest version_name must be the version followed by an optional release name")
}
}
function tagged(version) {
return fs.existsSync(".git") && execFileSync("git", ["tag", "--list", version]).toString().trim() !== ""
}
function set_release_version(manifest, component, name = "") {
if (![0, 1, 2].includes(component)) throw new Error("Version component must be 0, 1 or 2")
if (component === 2 && name) throw new Error("Only major and minor releases can be named")
@ -28,7 +38,7 @@ function set_release_version(manifest, component, name = "") {
manifest.version_name = [manifest.version, nameForRelease].filter(Boolean).join(" ")
}
async function add_beta(versionstr) {
async function beta_number() {
await fs.promises.mkdir(".build_cache", {recursive: true})
try {
await fs.promises.access(".git")
@ -42,7 +52,7 @@ async function add_beta(versionstr) {
catch {
; // Not in a git directory - don't do anything
}
return versionstr + "pre" + (await fs.promises.readFile(".build_cache/count", {encoding: "utf8"})).trim()
return (await fs.promises.readFile(".build_cache/count", {encoding: "utf8"})).trim()
}
async function get_hash() {
@ -97,18 +107,36 @@ function save_manifest(filename, manifest) {
fs.writeFileSync(filename, JSON.stringify(manifest, null, 4))
}
function set_beta_version(manifest, number, hash) {
const version = manifest.version
const name = release_name(manifest)
manifest.version = `${version}.${number}`
manifest.version_name = [`${version}pre${number}-${hash}`, name].filter(Boolean).join(" ")
}
async function main() {
let filename, manifest, releaseName
let filename, manifest
switch (process.argv[2]) {
case "bump": {
// Load src manifest and bump
case "next": {
filename = "./src/manifest.json"
manifest = require("." + filename)
if (!tagged(manifest.version)) throw new Error(`Version ${manifest.version} is not tagged`)
set_release_version(
manifest,
Number(process.argv[3]),
process.argv.slice(4).join(" "),
)
validate_release_version(manifest)
if (tagged(manifest.version)) throw new Error(`Version ${manifest.version} is already tagged`)
save_manifest(filename, manifest)
break
}
case "release": {
filename = "./src/manifest.json"
manifest = require("." + filename)
validate_release_version(manifest)
if (tagged(manifest.version)) throw new Error(`Version ${manifest.version} is already tagged`)
if (execFileSync("git", ["status", "--porcelain"]).toString().trim()) throw new Error("Release requires a clean worktree")
const changelog = fs.readFileSync("./CHANGELOG.md", "utf8")
const releaseHeading = `Release ${manifest.version} / Unreleased`
const releaseNotes = changelog
@ -127,8 +155,7 @@ async function main() {
"./CHANGELOG.md",
changelog.replace(releaseNotes, () => datedReleaseNotes),
)
save_manifest(filename, manifest)
execFileSync("git", ["add", filename, "./CHANGELOG.md"])
execFileSync("git", ["add", "./CHANGELOG.md"])
execFileSync("git", [
"commit",
"--cleanup=verbatim",
@ -147,9 +174,9 @@ async function main() {
case "beta":
filename = "./build/manifest.json"
manifest = require("." + filename)
releaseName = release_name(manifest)
manifest.version = await add_beta(manifest.version)
manifest.version_name = [manifest.version + "-" + (await get_hash()), releaseName].filter(Boolean).join(" ")
validate_release_version(manifest)
if (tagged(manifest.version)) throw new Error(`Version ${manifest.version} is already tagged`)
set_beta_version(manifest, await beta_number(), await get_hash())
manifest.applications.gecko.update_url =
"https://tridactyl.cmcaine.co.uk/betas/updates.json"
@ -173,4 +200,4 @@ async function main() {
if (require.main === module) main()
module.exports = { set_release_version }
module.exports = { set_beta_version, set_release_version }

View file

@ -1,4 +1,4 @@
const { set_release_version } = require("./version")
const { set_beta_version, set_release_version } = require("./version")
test("manages major and minor release names", () => {
const manifest = { version: "1.24.6", version_name: "1.24.6" }
@ -15,4 +15,8 @@ test("manages major and minor release names", () => {
expect(() =>
set_release_version({ version: "1.25.0" }, 2, "Carpenter"),
).toThrow()
set_beta_version(manifest, "7685", "1ac287cf")
expect(manifest.version).toBe("2.0.0.7685")
expect(manifest.version_name).toBe("2.0.0pre7685-1ac287cf Joiner")
})

View file

@ -130,6 +130,7 @@ const logger = new Logging.Logger("excmd")
/** @hidden **/
const TRI_VERSION = getTriVersion()
const TRI_VERSION_NAME = getTriVersionName()
const IS_BETA = browser.runtime.getManifest().applications?.gecko?.id?.includes(".betas") || false
//#content_helper
// {
@ -783,7 +784,7 @@ export async function native() {
*/
//#background
export async function nativeinstall() {
const tag = TRI_VERSION.includes("pre") ? "master" : TRI_VERSION
const tag = IS_BETA ? "master" : TRI_VERSION
let done
const installstr = (await config.get("nativeinstallcmd")).replace("%TAG", tag)
await yank(installstr)
@ -922,7 +923,7 @@ export async function updatenative(interactive = true) {
return
}
const tag = TRI_VERSION.includes("pre") ? "master" : TRI_VERSION
const tag = IS_BETA ? "master" : TRI_VERSION
const update_command = (await config.get("nativeinstallcmd")).replace("%TAG", tag)
const native_version = await Native.getNativeMessengerVersion()

View file

@ -9,7 +9,7 @@
import SemverCompare from "semver-compare"
import * as Config from "@src/lib/config"
import * as Logging from "@src/lib/logging"
import { getTriVersion } from "@src/lib/webext"
import { getTriVersion, getTriVersionName } from "@src/lib/webext"
const logger = new Logging.Logger("updates")
@ -83,22 +83,10 @@ export function updateLatestNaggedVersion(version: TriVersionFeedItem) {
}
export function getInstalledPatchVersion() {
// We're currently numbering our releases as
// maj.min.patch-numcommits-githash,
// e.g. 1.14.9-138-gaab4355. Even more problematically, our
// prereleases have maj.min.patch the same as the _preceding
// release_, not the _next_ release - 1.14.9-138 actually
// _follows_ 1.14.9. As a result, if we used TRI_VERSION directly,
// all of our beta users would be incorrectly notified for stable
// releases of code that they're well past.
//
// To address this, we ignore our git version, depend on firefox
// to automatically update us if we're on the beta channel, and
// disregard the pre-release information entirely when doing our
// own update check.
return TRI_VERSION.replace(/pre.*/, "")
// Beta versions use a fourth component for Firefox's updater.
return TRI_VERSION.split(".", 3).join(".")
}
export function getInstalledVersion() {
return TRI_VERSION
return getTriVersionName()
}

View file

@ -1,8 +1,8 @@
{
"manifest_version": 2,
"name": "Tridactyl",
"version": "1.24.6",
"version_name": "1.24.6",
"version": "1.25.0",
"version_name": "1.25.0 Carpenter",
"icons": {
"64": "static/logo/Tridactyl_64px.png",
"100": "static/logo/Tridactyl_100px.png",