Skip to content

Commit

Permalink
Add Opera release update script
Browse files Browse the repository at this point in the history
  • Loading branch information
caugner committed Jan 31, 2025
1 parent 70ecabb commit 5b9163c
Show file tree
Hide file tree
Showing 5 changed files with 340 additions and 0 deletions.
32 changes: 32 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"typescript": "~5.7.2",
"web-features": "^2.15.0",
"web-specs": "^3.0.0",
"xml2js": "^0.6.2",
"yargs": "~17.7.0"
},
"scripts": {
Expand Down
37 changes: 37 additions & 0 deletions scripts/update-browser-releases/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import yargs from 'yargs';
import { updateChromiumReleases } from './chrome.js';
import { updateEdgeReleases } from './edge.js';
import { updateFirefoxReleases } from './firefox.js';
import { updateOperaReleases } from './opera.js';
import { updateSafariReleases } from './safari.js';

const argv = yargs(process.argv.slice(2))
Expand All @@ -29,6 +30,11 @@ const argv = yargs(process.argv.slice(2))
type: 'boolean',
group: 'Engine selection:',
})
.option('opera', {
describe: 'Update Opera',
type: 'boolean',
group: 'Engine selection:',
})
.option('safari', {
describe: 'Update Apple Safari',
type: 'boolean',
Expand Down Expand Up @@ -65,12 +71,14 @@ const updateAllBrowsers =
argv['webview'] ||
argv['firefox'] ||
argv['edge'] ||
argv['opera'] ||
argv['safari']
);
const updateChrome = argv['chrome'] || updateAllBrowsers;
const updateWebview = argv['webview'] || updateAllBrowsers;
const updateFirefox = argv['firefox'] || updateAllBrowsers;
const updateEdge = argv['edge'] || updateAllBrowsers;
const updateOpera = argv['opera'] || updateAllBrowsers;
const updateSafari = argv['safari'] || updateAllBrowsers;
const updateAllDevices =
argv['alldevices'] || !(argv['mobile'] || argv['desktop']);
Expand Down Expand Up @@ -163,6 +171,25 @@ const options = {
firefoxScheduleURL:
'https://whattrainisitnow.com/api/release/schedule/?version=',
},
opera_desktop: {
browserName: 'Opera for Desktop',
bcdFile: './browsers/opera.json',
bcdBrowserName: 'opera',
skippedReleases: [],
releaseFeedURL: 'https://blogs.opera.com/desktop/category/stable-2/feed/',
titleVersionPattern: /^Opera (\d+)$/,
descriptionEngineVersionPattern: /Chromium (\d+)/,
},
opera_android: {
browserName: 'Opera for Android',
bcdFile: './browsers/opera_android.json',
bcdBrowserName: 'opera_android',
skippedReleases: [],
releaseFeedURL: 'https://forums.opera.com/category/20.rss',
releaseFilterCreator: ['abitkulova'],
titleVersionPattern: /^Opera for Android (\d+)$/,
descriptionEngineVersionPattern: /Chromium (\d+)/,
},
safari_desktop: {
browserName: 'Safari for Desktop',
bcdFile: './browsers/safari.json',
Expand Down Expand Up @@ -224,6 +251,16 @@ if (updateFirefox && updateMobile) {
result += (result && add ? '\n' : '') + add;
}

if (updateOpera && updateDesktop) {
const add = await updateOperaReleases(options.opera_desktop);
result += (result && add ? '\n' : '') + add;
}

if (updateOpera && updateMobile) {
const add = await updateOperaReleases(options.opera_android);
result += (result && add ? '\n' : '') + add;
}

if (updateSafari && updateDesktop) {
const add = await updateSafariReleases(options.safari_desktop);
result += (result && add ? '\n' : '') + add;
Expand Down
170 changes: 170 additions & 0 deletions scripts/update-browser-releases/opera.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import fs from 'node:fs/promises';

import stringify from '../lib/stringify-and-order-properties.js';

import {
createOrUpdateBrowserEntry,
getRSSItems,
RSSItem,
updateBrowserEntry,
} from './utils';

interface Release {
version: string;
date: string;
releaseNote: string;
channel: 'current';
engine: 'Blink';
engineVersion: string;
}

/**
* Extracts the latest release from the items.
* @param items the RSS items.
* @param titleVersionPattern the pattern to match the title and extract the version.
* @param descriptionEngineVersionPattern the pattern to match the description and extract the engine version.
* @returns the latest release, if found, otherwise null.
*/
const findRelease = (
items: RSSItem[],
titleVersionPattern: RegExp,
descriptionEngineVersionPattern: RegExp,
): Release | null => {
const item = items.find(
(item) =>
titleVersionPattern.test(item.title) &&
descriptionEngineVersionPattern.test(item.description),
);

if (!item) {
return null;
}

const version = (
item.title.match(titleVersionPattern) as RegExpMatchArray
)[1];
const date = new Date(item.pubDate).toISOString().split('T')[0];
const releaseNote = item.link;
const engineVersion = (
item.description.match(descriptionEngineVersionPattern) as RegExpMatchArray
)[1];

return {
version,
date,
releaseNote,
channel: 'current',
engine: 'Blink',
engineVersion,
};
};

/**
* Converts a message into a GFM noteblock.
* @param type the type of the noteblock.
* @param message the message of the noteblock.
* @returns the message as a GFM noteblock.
*/
const gfmNoteblock = (type: 'INFO' | 'WARN', message: string) =>
`> [!${type}]\n${message
.split('\n')
.map((line) => `> ${line}`)
.join('\n')}`;

/**
* Updates the JSON files listing the Opera browser releases.
* @param options The list of options for this type of Safari.
* @returns The log of what has been generated (empty if nothing)
*/
export const updateOperaReleases = async (options) => {
const browser = options.bcdBrowserName;

const isDesktop = browser === 'opera';

let result = '';

const items = await getRSSItems(options.releaseFeedURL);

const release = findRelease(
items.filter((item) =>
options.releaseFilterCreator?.includes(item['dc:creator'] ?? true),
),
options.titleVersionPattern,
options.descriptionEngineVersionPattern,
);

if (!release) {
return gfmNoteblock(
'INFO',
`**${options.browserName}**: No release announcement found among ${items.length} items in [this RSS feed](<${options.releaseFeedURL}>).`,
);
}

const file = await fs.readFile(`${options.bcdFile}`, 'utf-8');
const data = JSON.parse(file.toString());

const current = structuredClone(
data.browsers[browser].releases[release.version],
);

if (isDesktop && !current) {
return gfmNoteblock(
'WARN',
`Latest stable **${options.browserName}** release **${release.version}** not yet tracked.`,
);
}

result += createOrUpdateBrowserEntry(
data,
browser,
release.version,
release.channel,
release.engine,
release.engineVersion,
release.date,
release.releaseNote,
);

// Set previous release to "retired".
const previousVersion = String(Number(release.version) - 1);
result += updateBrowserEntry(
data,
browser,
previousVersion,
undefined,
'retired',
undefined,
undefined,
);

if (isDesktop) {
// 1. Set next release to "beta".
result += createOrUpdateBrowserEntry(
data,
browser,
String(Number(release.version) + 1),
'beta',
release.engine,
String(Number(release.engineVersion) + 1),
);

// 2. Add another release as "nightly".
result += createOrUpdateBrowserEntry(
data,
browser,
String(Number(release.version) + 2),
'nightly',
release.engine,
String(Number(release.engineVersion) + 2),
);
}

await fs.writeFile(`./${options.bcdFile}`, stringify(data) + '\n');

// Returns the log
if (result) {
result = `### Updates for ${options.browserName}${result}`;
}

return result;
};
Loading

0 comments on commit 5b9163c

Please sign in to comment.