diff --git a/readme.md b/readme.md index e2ecee41..db00c6ab 100644 --- a/readme.md +++ b/readme.md @@ -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 diff --git a/scripts/version.js b/scripts/version.js index 8855ee8d..5fe91580 100755 --- a/scripts/version.js +++ b/scripts/version.js @@ -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 } diff --git a/scripts/version.test.js b/scripts/version.test.js index 29a4de3d..d2461fc1 100644 --- a/scripts/version.test.js +++ b/scripts/version.test.js @@ -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") }) diff --git a/src/excmds.ts b/src/excmds.ts index 2630d8f4..81cca355 100644 --- a/src/excmds.ts +++ b/src/excmds.ts @@ -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() diff --git a/src/lib/updates.ts b/src/lib/updates.ts index a4d650e4..94cf758f 100644 --- a/src/lib/updates.ts +++ b/src/lib/updates.ts @@ -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() } diff --git a/src/manifest.json b/src/manifest.json index 9b0136d9..dae1797e 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -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",