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

#8343: handle 4 digit extension version numbers #8346

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions scripts/__snapshots__/manifest.test.js.snap

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 11 additions & 13 deletions scripts/manifest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ import Policy from "csp-parse";
import { normalizeManifestPermissions } from "webext-permissions";
import { excludeDuplicatePatterns } from "webext-patterns";

function getVersion(env, isBetaListing) {
function getVersion(env) {
const stageMap = {
alpha: 1000,
beta: 2000,
release: 3000,
};

// `manifest.json` only supports numbers in the version, so use the semver
Expand All @@ -32,19 +33,16 @@ function getVersion(env, isBetaListing) {
);
const { version, stage, stageNumber } = match.groups;

// Add 4th digit for alpha/beta release builds. Used to update the extension BETA listing in the Chrome Web Store.
if (isBetaListing) {
if (stage && stageNumber) {
// Ex: 1.8.13-alpha.1 -> 1.8.13.1001
// Ex: 1.8.13-beta.55 -> 1.8.13.2055
return `${version}.${stageMap[stage] + Number(stageNumber)}`;
}

// Ex: 1.8.13.3000 -- Ensures that the release build version number is greater than the alpha/beta build version numbers
return `${version}.3000`;
// Add 4th digit for differentiating alpha/beta/stable release builds.
// Used primarily to update the extension BETA listing in the Chrome Web Store.
if (stage && stageNumber) {
// Ex: 1.8.13-alpha.1 -> 1.8.13.1001
// Ex: 1.8.13-beta.55 -> 1.8.13.2055
return `${version}.${stageMap[stage] + Number(stageNumber)}`;
}

return version;
// Ex: 1.8.13.3000 -- Ensures that the release build version number is greater than the alpha/beta build version numbers
return `${version}.${stageMap.release}`;
}

function getVersionName(env, isProduction) {
Expand Down Expand Up @@ -146,7 +144,7 @@ function addInternalUrlsToContentScripts(manifest, internal) {
function customizeManifest(manifestV2, options = {}) {
const { isProduction, manifestVersion, env = {}, isBeta } = options;
const manifest = structuredClone(manifestV2);
manifest.version = getVersion(env, isBeta);
manifest.version = getVersion(env);
manifest.version_name = getVersionName(env, isProduction);

if (!isProduction) {
Expand Down
98 changes: 68 additions & 30 deletions scripts/manifest.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,45 +15,83 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/* eslint-disable @shopify/jest/no-snapshots -- We want to specifically commit the entire customized manifest as a snapshot */
/* eslint-disable no-restricted-imports -- Aliases don't work outside built files */

import { omit } from "lodash";
import manifest from "../src/manifest.json";
import { loadEnv } from "./env.mjs";
import customizeManifest from "./manifest.mjs";

loadEnv();

const cleanCustomize = (...args) =>
omit(customizeManifest(...args), ["version", "version_name", "key"]);
const cleanCustomize = (...args) => omit(customizeManifest(...args), ["key"]);

describe("customizeManifest", () => {
test("mv2", () => {
expect(
cleanCustomize(manifest, {
env: process.env,
isProduction: true,
}),
).toMatchSnapshot();
});
test("mv3", () => {
expect(
cleanCustomize(manifest, {
env: process.env,
isProduction: true,
manifestVersion: 3,
}),
).toMatchSnapshot();
describe("release builds", () => {
test("mv2", () => {
expect(
cleanCustomize(manifest, {
// eslint-disable-next-line camelcase -- auto-inserted
env: { ...process.env, npm_package_version: "1.8.13" },
isProduction: true,
}),
).toMatchSnapshot();
});

test("mv3", () => {
expect(
cleanCustomize(manifest, {
// eslint-disable-next-line camelcase -- auto-inserted
env: { ...process.env, npm_package_version: "1.8.13" },
isProduction: true,
manifestVersion: 3,
}),
).toMatchSnapshot();
});

test("beta", () => {
expect(
cleanCustomize(manifest, {
// eslint-disable-next-line camelcase -- auto-inserted
env: { ...process.env, npm_package_version: "1.8.13" },
isProduction: true,
manifestVersion: 3,
isBeta: true,
}),
).toMatchSnapshot();
});
});
test("beta", () => {
expect(
cleanCustomize(manifest, {
env: process.env,
isProduction: true,
manifestVersion: 3,
isBeta: true,
}),
).toMatchSnapshot();

describe("four digit versioning", () => {
test("alpha version", () => {
expect(
cleanCustomize(manifest, {
// eslint-disable-next-line camelcase -- auto-inserted
env: { ...process.env, npm_package_version: "1.8.13-alpha.123" },
isProduction: true,
manifestVersion: 3,
}),
).toContainEntry(["version", "1.8.13.1123"]);
});

test("beta version", () => {
expect(
cleanCustomize(manifest, {
// eslint-disable-next-line camelcase -- auto-inserted
env: { ...process.env, npm_package_version: "1.8.13-beta.123" },
isProduction: true,
manifestVersion: 3,
}),
).toContainEntry(["version", "1.8.13.2123"]);
});

test("release version", () => {
expect(
cleanCustomize(manifest, {
// eslint-disable-next-line camelcase -- auto-inserted
env: { ...process.env, npm_package_version: "1.8.13" },
isProduction: true,
manifestVersion: 3,
}),
).toContainEntry(["version", "1.8.13.3000"]);
});
});
});
7 changes: 2 additions & 5 deletions src/background/backgroundPlatform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import type { NetworkRequestConfig } from "@/types/networkTypes";
import type { RemoteResponse } from "@/types/contract";
import { performConfiguredRequest } from "@/background/requests";
import BackgroundLogger from "@/telemetry/BackgroundLogger";
import { validateSemVerString } from "@/types/helpers";
import { PlatformBase } from "@/platform/platformBase";
import { getExtensionVersion } from "@/utils/extensionUtils";

/**
* Background platform implementation. Currently, just makes API requests.
Expand All @@ -40,10 +40,7 @@ class BackgroundPlatform extends PlatformBase {
});

constructor() {
super(
"background",
validateSemVerString(browser.runtime.getManifest().version),
);
super("background", getExtensionVersion());
}

override get logger(): PlatformProtocol["logger"] {
Expand Down
8 changes: 4 additions & 4 deletions src/background/deploymentUpdater.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
getModComponentState,
saveModComponentState,
} from "@/store/extensionsStorage";
import { uuidv4, validateSemVerString } from "@/types/helpers";
import { uuidv4, normalizeSemVerString } from "@/types/helpers";
import { appApiMock } from "@/testUtils/appApiMock";
import { omit } from "lodash";
import { syncDeployments } from "@/background/deploymentUpdater";
Expand Down Expand Up @@ -68,8 +68,8 @@ jest.mock("@/store/settings/settingsStorage");
jest.mock("@/hooks/useRefreshRegistries");

jest.mock("@/utils/extensionUtils", () => ({
...jest.requireActual("@/utils/extensionUtils"),
forEachTab: jest.fn(),
getExtensionVersion: () => browser.runtime.getManifest().version,
}));

// Override manual mock to support `expect` assertions
Expand Down Expand Up @@ -380,7 +380,7 @@ describe("syncDeployments", () => {
_recipe: {
id: deployment.package.package_id,
name: deployment.package.name,
version: validateSemVerString("0.0.1"),
version: normalizeSemVerString("0.0.1"),
updated_at: deployment.updated_at,
sharing: sharingDefinitionFactory(),
},
Expand Down Expand Up @@ -438,7 +438,7 @@ describe("syncDeployments", () => {
_recipe: {
id: deployment.package.package_id,
name: deployment.package.name,
version: validateSemVerString("0.0.1"),
version: normalizeSemVerString("0.0.1"),
updated_at: deployment.updated_at,
sharing: sharingDefinitionFactory(),
},
Expand Down
2 changes: 1 addition & 1 deletion src/background/deploymentUpdater.ts
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ async function activateDeploymentsInBackground({
);

// Version to report to the server.
const { version: extensionVersionString } = browser.runtime.getManifest();
const extensionVersionString = getExtensionVersion();
const extensionVersion = parseSemVer(extensionVersionString);

const deploymentsByActivationMethod = await Promise.all(
Expand Down
9 changes: 6 additions & 3 deletions src/background/installer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ import {
import { Events } from "@/telemetry/events";
import { DEFAULT_SERVICE_URL, UNINSTALL_URL } from "@/urlConstants";
import { CONTROL_ROOM_TOKEN_INTEGRATION_ID } from "@/integrations/constants";
import { getExtensionConsoleUrl } from "@/utils/extensionUtils";
import {
getExtensionConsoleUrl,
getExtensionVersion,
} from "@/utils/extensionUtils";
import { oncePerSession } from "@/mv3/SessionStorage";
import { resetFeatureFlagsCache } from "@/auth/featureFlagStorage";

Expand Down Expand Up @@ -223,7 +226,7 @@ export async function showInstallPage({
// https://developer.chrome.com/docs/extensions/reference/runtime/#event-onInstalled
// https://developer.chrome.com/docs/extensions/reference/runtime/#type-OnInstalledReason
console.debug("onInstalled", { reason, previousVersion });
const { version } = browser.runtime.getManifest();
const version = getExtensionVersion();

if (reason === "install") {
void recordEvent({
Expand Down Expand Up @@ -309,7 +312,7 @@ export function getAvailableVersion(): typeof _availableVersion {
*/
export function isUpdateAvailable(): boolean {
const available = getAvailableVersion();
const installed = browser.runtime.getManifest().version;
const installed = getExtensionVersion();
return (
Boolean(available) && installed !== available && gt(available, installed)
);
Expand Down
7 changes: 6 additions & 1 deletion src/background/messenger/external/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,14 @@
import { _liftBackground as liftExternal } from "@/background/externalProtocol";
import * as local from "@/background/messenger/external/_implementation";
import { readPartnerAuthData } from "@/auth/authStorage";
import { getExtensionVersion } from "@/utils/extensionUtils";

export const connectPage = liftExternal("CONNECT_PAGE", async () =>
browser.runtime.getManifest(),
// Ensure the version we send to the app is a valid semver.
({
...browser.runtime.getManifest(),
version: getExtensionVersion(),
}),
);

export const setExtensionAuth = liftExternal(
Expand Down
1 change: 1 addition & 0 deletions src/background/restrictUnauthenticatedUrlAccess.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jest.mock("@/auth/authStorage", () => ({
}));

jest.mock("@/utils/extensionUtils", () => ({
...jest.requireActual("@/utils/extensionUtils"),
forEachTab: jest.fn(),
}));

Expand Down
13 changes: 6 additions & 7 deletions src/background/telemetry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { count as registrySize } from "@/registry/packageRegistry";
import { count as logSize } from "@/telemetry/logging";
import { count as traceSize } from "@/telemetry/trace";
import { getUUID } from "@/telemetry/telemetryHelpers";
import { getTabsWithAccess } from "@/utils/extensionUtils";
import { getExtensionVersion, getTabsWithAccess } from "@/utils/extensionUtils";
import { type Event } from "@/telemetry/events";

const EVENT_BUFFER_DEBOUNCE_MS = 2000;
Expand Down Expand Up @@ -274,7 +274,8 @@ export async function TEST_flushAll(): Promise<void> {

async function collectUserSummary(): Promise<UserSummary> {
const { os } = await browser.runtime.getPlatformInfo();
const { version, version_name: versionName } = browser.runtime.getManifest();
const { version_name: versionName } = browser.runtime.getManifest();
const version = getExtensionVersion();
// Not supported on Chromium, and may require additional permissions
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/getBrowserInfo
// const {name: browserName} = await browser.runtime.getBrowserInfo();
Expand Down Expand Up @@ -336,11 +337,9 @@ export async function recordEvent({
data: UnknownObject | undefined;
}): Promise<void> {
if (await allowsTrack()) {
const {
version,
version_name: versionName,
manifest_version: manifestVersion,
} = browser.runtime.getManifest();
const { version_name: versionName, manifest_version: manifestVersion } =
browser.runtime.getManifest();
const version = getExtensionVersion();
const telemetryEvent = {
uid: await getUUID(),
event,
Expand Down
Loading
Loading