From ceb8a2cb8d7a1bb62fad5ba1c12eda1847424e59 Mon Sep 17 00:00:00 2001 From: David Sanders Date: Mon, 12 Jun 2023 15:52:21 -0700 Subject: [PATCH] feat: source of truth for version support --- src/data.js | 23 ++++- src/index.js | 20 ++++- src/routes/history.js | 4 +- src/routes/home.js | 11 ++- src/routes/pr.js | 4 +- src/routes/release.js | 8 +- src/routes/releases.js | 4 +- src/versions-support.json | 177 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 231 insertions(+), 20 deletions(-) create mode 100644 src/versions-support.json diff --git a/src/data.js b/src/data.js index 07ecd87..75472d5 100644 --- a/src/data.js +++ b/src/data.js @@ -4,6 +4,8 @@ const { Octokit } = require('@octokit/rest'); const ExpiryMap = require('expiry-map'); const pMemoize = require('p-memoize'); const semver = require('semver'); +const fs = require('fs'); +const path = require('path'); let octokit = null; const getOctokit = async () => { @@ -30,15 +32,28 @@ const getOctokit = async () => { return octokit; }; -const getReleasesOrUpdate = pMemoize( +const getVersionsOrUpdate = pMemoize( async () => { const response = await fetch.default('https://electronjs.org/headers/index.json'); const releases = await response.json(); - return releases.sort((a, b) => semver.compare(b.version, a.version)); + const support = JSON.parse(fs.readFileSync(path.join(__dirname, 'versions-support.json'))); + return { + support: support.map((version) => { + const stableRelease = + releases.find((release) => release.version === `${version.major}.0.0`) !== undefined; + const endOfLife = version.endOfLife; + return { + ...version, + isSupported: !endOfLife || new Date() <= new Date(endOfLife), + isStable: stableRelease, + }; + }), + releases: releases.sort((a, b) => semver.compare(b.version, a.version)), + }; }, { cache: new ExpiryMap(60 * 1000), - cacheKey: () => 'releases', + cacheKey: () => 'versions', }, ); @@ -158,7 +173,7 @@ const getTSDefs = pMemoize( module.exports = { getGitHubRelease, - getReleasesOrUpdate, + getVersionsOrUpdate, getActiveReleasesOrUpdate, getAllSudowoodoReleasesOrUpdate, getPR, diff --git a/src/index.js b/src/index.js index 753b57f..dcdf72f 100644 --- a/src/index.js +++ b/src/index.js @@ -3,7 +3,7 @@ const exphbs = require('express-handlebars'); const path = require('path'); const a = require('./utils/a'); -const { getReleasesOrUpdate, getActiveReleasesOrUpdate } = require('./data'); +const { getVersionsOrUpdate, getActiveReleasesOrUpdate } = require('./data'); const app = express(); @@ -25,7 +25,23 @@ app.get( '/releases.json', a(async (req, res) => { res.setHeader('Access-Control-Allow-Origin', '*'); - res.json(await getReleasesOrUpdate()); + res.json((await getVersionsOrUpdate()).releases); + }), +); + +app.get( + '/versions.json', + a(async (req, res) => { + res.setHeader('Access-Control-Allow-Origin', '*'); + res.json(await getVersionsOrUpdate()); + }), +); + +app.get( + '/support.json', + a(async (req, res) => { + res.setHeader('Access-Control-Allow-Origin', '*'); + res.json((await getVersionsOrUpdate()).support); }), ); diff --git a/src/routes/history.js b/src/routes/history.js index bead912..3507271 100644 --- a/src/routes/history.js +++ b/src/routes/history.js @@ -1,7 +1,7 @@ const { Router } = require('express'); const a = require('../utils/a'); -const { getReleasesOrUpdate } = require('../data'); +const { getVersionsOrUpdate } = require('../data'); const router = new Router(); @@ -14,7 +14,7 @@ router.get('/', (req, res) => router.get( '/:date', a(async (req, res) => { - const releases = await getReleasesOrUpdate(); + const { releases } = await getVersionsOrUpdate(); const onDate = releases.filter((r) => r.date === req.params.date); if (onDate.length === 0) return res.redirect('/history'); res.render('date', { diff --git a/src/routes/home.js b/src/routes/home.js index 0c03fb2..416ec6c 100644 --- a/src/routes/home.js +++ b/src/routes/home.js @@ -3,7 +3,7 @@ const Handlebars = require('handlebars'); const semver = require('semver'); const a = require('../utils/a'); -const { getReleasesOrUpdate, getActiveReleasesOrUpdate } = require('../data'); +const { getVersionsOrUpdate, getActiveReleasesOrUpdate } = require('../data'); const { timeSince, minutesSince } = require('../utils/format-time'); const router = new Router(); @@ -62,8 +62,8 @@ Handlebars.registerPartial('releaseSquare', function (release) { router.get( '/', a(async (req, res) => { - const [releases, activeReleases] = await Promise.all([ - getReleasesOrUpdate(), + const [{ releases, support }, activeReleases] = await Promise.all([ + getVersionsOrUpdate(), getActiveReleasesOrUpdate(), ]); const lastNightly = releases.find((r) => semver.parse(r.version).prerelease[0] === 'nightly'); @@ -74,7 +74,10 @@ router.get( ); const lastStable = releases.find((r) => semver.parse(r.version).prerelease.length === 0); const stableMajor = semver.parse(lastStable.version).major; - const latestSupported = [stableMajor, stableMajor - 1, stableMajor - 2].map((major) => + const supportedMajors = support + .filter((version) => version.isSupported && version.isStable) + .map((version) => version.major); + const latestSupported = supportedMajors.map((major) => releases.find((r) => semver.parse(r.version).major === major), ); if (semver.parse(lastPreRelease.version).major <= stableMajor) { diff --git a/src/routes/pr.js b/src/routes/pr.js index c351f54..26deb57 100644 --- a/src/routes/pr.js +++ b/src/routes/pr.js @@ -2,12 +2,12 @@ const { Router } = require('express'); const semver = require('semver'); const a = require('../utils/a'); -const { compareTagToCommit, getReleasesOrUpdate, getPR, getPRComments } = require('../data'); +const { compareTagToCommit, getVersionsOrUpdate, getPR, getPRComments } = require('../data'); const router = new Router(); async function getPRReleaseStatus(prNumber) { - const releases = [...(await getReleasesOrUpdate())].reverse(); + const releases = [...(await getVersionsOrUpdate()).releases].reverse(); const [prInfo, comments] = await Promise.all([getPR(prNumber), getPRComments(prNumber)]); if (!prInfo) return null; diff --git a/src/routes/release.js b/src/routes/release.js index 71de819..69a8c6a 100644 --- a/src/routes/release.js +++ b/src/routes/release.js @@ -8,7 +8,7 @@ const Prism = require('prismjs'); const semver = require('semver'); const a = require('../utils/a'); -const { getGitHubRelease, getReleasesOrUpdate, getTSDefs } = require('../data'); +const { getGitHubRelease, getVersionsOrUpdate, getTSDefs } = require('../data'); const window = new JSDOM('').window; const DOMPurify = createDOMPurify(window); @@ -59,7 +59,7 @@ Handlebars.registerHelper('markdownMergeHeaders', function (contentArr) { }); async function getValidVersionRange(startVersion, endVersion, res) { - const allReleases = await getReleasesOrUpdate(); + const { releases: allReleases } = await getVersionsOrUpdate(); const parsedStart = semver.parse(startVersion); const parsedEnd = semver.parse(endVersion); @@ -182,9 +182,9 @@ router.get( '/:version', a(async (req, res) => { const version = req.params.version; - const [release, allReleases] = await Promise.all([ + const [release, { releases: allReleases }] = await Promise.all([ getGitHubRelease(version), - getReleasesOrUpdate(), + getVersionsOrUpdate(), ]); if (!release) { return res.redirect('/'); diff --git a/src/routes/releases.js b/src/routes/releases.js index e152a4c..83fc7ce 100644 --- a/src/routes/releases.js +++ b/src/routes/releases.js @@ -2,7 +2,7 @@ const { Router } = require('express'); const paginate = require('express-paginate'); const Handlebars = require('handlebars'); const a = require('../utils/a'); -const { getGitHubRelease, getReleasesOrUpdate } = require('../data'); +const { getGitHubRelease, getVersionsOrUpdate } = require('../data'); const semver = require('semver'); const router = new Router(); @@ -75,7 +75,7 @@ router.get( filter = ({ version }) => version.includes('nightly'); } - const releases = await getReleasesOrUpdate(); + const { releases } = await getVersionsOrUpdate(); const { page, limit, version } = req.query; const releasesFromChannel = releases.filter(filter); const major = Number(version); diff --git a/src/versions-support.json b/src/versions-support.json new file mode 100644 index 0000000..186a96e --- /dev/null +++ b/src/versions-support.json @@ -0,0 +1,177 @@ +[ + { + "major": 26, + "alpha": "2023-06-01", + "beta": "2023-06-27", + "stable": "2023-08-08", + "endOfLife": null + }, + { + "major": 25, + "alpha": "2023-04-10", + "beta": "2023-05-02", + "stable": "2023-05-30", + "endOfLife": "2023-12-05" + }, + { + "major": 24, + "alpha": "2023-02-09", + "beta": "2023-03-07", + "stable": "2023-04-04", + "endOfLife": "2023-10-03" + }, + { + "major": 23, + "alpha": "2022-12-01", + "beta": "2023-01-10", + "stable": "2023-02-07", + "endOfLife": "2023-08-08" + }, + { + "major": 22, + "alpha": "2022-09-29", + "beta": "2022-10-25", + "stable": "2022-11-29", + "endOfLife": "2023-10-10" + }, + { + "major": 21, + "alpha": "2022-08-04", + "beta": "2022-08-30", + "stable": "2022-09-27", + "endOfLife": "2023-04-04" + }, + { + "major": 20, + "alpha": "2022-05-26", + "beta": "2022-06-21", + "stable": "2022-08-02", + "endOfLife": "2023-02-07" + }, + { + "major": 19, + "alpha": "2022-03-31", + "beta": "2022-04-26", + "stable": "2022-05-24", + "endOfLife": "2022-11-29" + }, + { + "major": 18, + "alpha": "2022-02-03", + "beta": "2022-03-03", + "stable": "2022-03-29", + "endOfLife": "2022-09-27" + }, + { + "major": 17, + "alpha": "2021-11-18", + "beta": "2022-01-06", + "stable": "2022-02-01", + "endOfLife": "2022-08-02" + }, + { + "major": 16, + "alpha": "2021-09-23", + "beta": "2021-10-20", + "stable": "2021-11-16", + "endOfLife": "2022-05-24" + }, + { + "major": 15, + "alpha": "2021-07-20", + "beta": "2021-09-01", + "stable": "2021-09-21", + "endOfLife": "2022-05-24" + }, + { + "major": 14, + "alpha": null, + "beta": "2021-05-27", + "stable": "2021-08-31", + "endOfLife": "2022-03-29" + }, + { + "major": 13, + "alpha": null, + "beta": "2021-03-04", + "stable": "2021-05-25", + "endOfLife": "2022-02-01" + }, + { + "major": 12, + "alpha": null, + "beta": "2020-11-19", + "stable": "2021-03-02", + "endOfLife": "2021-11-16" + }, + { + "major": 11, + "alpha": null, + "beta": "2020-08-27", + "stable": "2020-11-17", + "endOfLife": "2021-08-31" + }, + { + "major": 10, + "alpha": null, + "beta": "2020-05-21", + "stable": "2020-08-25", + "endOfLife": "2021-05-25" + }, + { + "major": 9, + "alpha": null, + "beta": "2020-02-06", + "stable": "2020-05-19", + "endOfLife": "2021-03-02" + }, + { + "major": 8, + "alpha": null, + "beta": "2019-10-24", + "stable": "2020-02-04", + "endOfLife": "2020-11-17" + }, + { + "major": 7, + "alpha": null, + "beta": "2019-08-01", + "stable": "2019-10-22", + "endOfLife": "2020-08-25" + }, + { + "major": 6, + "alpha": null, + "beta": "2019-04-25", + "stable": "2019-07-30", + "endOfLife": "2020-05-19" + }, + { + "major": 5, + "alpha": null, + "beta": "2019-01-22", + "stable": "2019-04-23", + "endOfLife": "2020-02-04" + }, + { + "major": 4, + "alpha": null, + "beta": "2018-10-11", + "stable": "2018-12-20", + "endOfLife": "2019-10-22" + }, + { + "major": 3, + "alpha": null, + "beta": "2018-06-21", + "stable": "2018-09-18", + "endOfLife": "2019-07-30" + }, + { + "major": 2, + "alpha": null, + "beta": "2018-02-21", + "stable": "2018-05-01", + "endOfLife": "2019-04-23" + } +]