From b4431eb6f49c786acff1cd13f06b0d92785ffc63 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 13 Sep 2025 15:08:59 +0200 Subject: [PATCH 01/16] add subfloder for proposals --- .gitignore | 1 + bin/lts.js | 11 ++- lib/index.js | 107 +++++++++++++++++++++------- lts.json | 60 ++++------------ package.json | 1 + release-schedule-proposal/README.md | 9 +++ 6 files changed, 117 insertions(+), 72 deletions(-) create mode 100644 release-schedule-proposal/README.md diff --git a/.gitignore b/.gitignore index 5e99da5..9096800 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,4 @@ jspm_packages *.html *.png *.svg +!release-schedule-proposal/*.svg diff --git a/bin/lts.js b/bin/lts.js index 3752e8c..922eb1f 100644 --- a/bin/lts.js +++ b/bin/lts.js @@ -4,9 +4,9 @@ const Path = require('path'); const Bossy = require('bossy'); const Lib = require('../lib'); const now = new Date(); -const oneYearFromNow = new Date(); +const oneYearFromNow = new Date('2035-01-01'); -oneYearFromNow.setFullYear(now.getFullYear() + 1); +// oneYearFromNow.setFullYear(now.getFullYear() + 1); const cliArgs = { 'd': { @@ -112,3 +112,10 @@ const options = { }; Lib.create(options); + +Lib.create({ + ...options, + queryStart: new Date('2029-09-01'), + queryEnd: new Date('2031-05-01'), + svg: options.svg.replace('.svg', '2030.svg'), +}); diff --git a/lib/index.js b/lib/index.js index ff99db3..356ceff 100644 --- a/lib/index.js +++ b/lib/index.js @@ -2,8 +2,12 @@ const Fs = require('fs'); const D3 = require('d3'); const D3Node = require('d3-node'); +const { Temporal } = require("@js-temporal/polyfill"); const styles = ` +.beta { + fill:rgb(240, 240, 75); +} .current { fill: #5fa04e; } @@ -13,7 +17,7 @@ const styles = ` .maintenance { fill: #b1bcc2; } -.unstable { +.unstable,.alpha { fill: #e99c40; } .bar-join { @@ -29,20 +33,75 @@ const styles = ` .axis--y .tick text { text-anchor: end; } -.label { +.label,.label-beta { fill: #fff; font: 20px sans-serif; font-weight: 100; text-anchor: start; dominant-baseline: middle; text-transform: uppercase; +} +.label-beta{ + fill: #000; }`; +const schedule = { + // TODO +}; + +console.log(`\n## ${schedule.title}`); +{ + const ___ = duration_s => Array.isArray(duration_s) ? + `\n - for even-numbered releases:${___(duration_s[0])}\n - for odd-numbered releases:${___(duration_s[1])}` : + ` ${duration_s ? Temporal.Duration.from(duration_s).months : 0} months`; + console.log(Object.entries(schedule).map(([key, duration], i) => key === 'title' ? '' : + ` ${i}. ${key.replace('D', ' d')}:${___(duration)}` + ).join('\n')); +} +{ + const durations = Object.entries(schedule).filter(c => c[0] !== 'title' && c[0] !== 'alphaDuration' && c[1]).map(c => c[1]); + const hasArray = durations.some(Array.isArray); + const __ = arr => arr.reduce((acc, dur) => acc+Temporal.Duration.from(dur).months, 0) + const ___ = () => hasArray ? + `\n - for even-numbered releases: ${__(durations.map(c => (Array.isArray(c) ? c[0] : c) || 'P0M'))} months\n - for odd-numbered releases: ${__(durations.map(c => (Array.isArray(c) ? c[1] : c) || 'P0M'))} months` : + ` ${__(durations)} months`; + console.log(`\n Total life span (from start of beta until end of maintenance):${___(schedule)}`) +} + +const __ = (duration_s, i) => Array.isArray(duration_s) ? duration_s[i % duration_s.length] : duration_s; + +function createDataEntry(start, i) { + const ret = {}; + + const alphaDuration = __(schedule.alphaDuration, i); + const betaDuration = __(schedule.betaDuration, i); + const currentDuration = __(schedule.currentDuration, i); + const activeDuration = __(schedule.activeDuration, i); + const maintenanceDuration = __(schedule.maintenanceDuration, i); + + if (alphaDuration) { + ret.alpha = start.toString(); + start = start.add(alphaDuration); + } + if (betaDuration) { + ret.beta = start.toString(); + start = start.add(betaDuration); + } + ret.start = start.toString(); + start = start.add(currentDuration); + if (activeDuration) { + ret.lts = start.toString(); + start = start.add(activeDuration); + } + ret.maintenance = start.toString(); + ret.end = start.add(maintenanceDuration).toString(); + return ret; +} + function parseInput (data, queryStart, queryEnd, excludeMain, projectName) { const output = []; - Object.keys(data).forEach((v) => { - const version = data[v]; + const addData = (v, version) => { const name = `${projectName} ${v.replace('v', '')}`; const current = version.start ? new Date(version.start) : null; const active = version.lts ? new Date(version.lts) : null; @@ -76,7 +135,20 @@ function parseInput (data, queryStart, queryEnd, excludeMain, projectName) { if (current < queryEnd && end > queryStart) { output.push({ name, type: 'current', start: current, end }); } - }); + if (version.beta) { + const start = new Date(version.beta); + output.push(({ name, type: 'beta', start, end: current })); + output.push(({ name, type: 'alpha', start: new Date(version.alpha), end: start })); + } + } + Object.entries(data).forEach(v => addData(...v, false)); + const queryEndPlainDate = Temporal.PlainDate.from(queryEnd.toISOString().slice(0, 10)); + for (let start = Temporal.PlainDate.from(data.v26.lts), i = 27; Temporal.PlainDate.compare(queryEndPlainDate, start) === 1; i++) { + const dataEntry = createDataEntry(start, i); + addData(`v${i}`, dataEntry); + const nextStart = Temporal.PlainDate.from(dataEntry.lts || dataEntry.maintenance); + start = nextStart; + } if (!excludeMain) { output.unshift({ @@ -92,7 +164,7 @@ function parseInput (data, queryStart, queryEnd, excludeMain, projectName) { function create (options) { - const { queryStart, queryEnd, html, svg: svgFile, png, animate, excludeMain, projectName, margin: marginInput, currentDateMarker } = options; + const { queryStart, queryEnd, html, svg: svgFile, png, animate, excludeMain, projectName, margin: marginInput } = options; const data = parseInput(options.data, queryStart, queryEnd, excludeMain, projectName); const d3n = new D3Node({ svgStyles: styles, d3Module: D3 }); const margin = marginInput || { top: 30, right: 30, bottom: 30, left: 110 }; @@ -108,7 +180,7 @@ function create (options) { .padding(0.3); const xAxis = D3.axisBottom(xScale) .tickSize(height) - .tickFormat(D3.timeFormat('%b %Y')); + .tickFormat(D3.timeFormat('%b%y')); const yAxis = D3.axisRight(yScale).tickSize(width); const svg = d3n.createSVG() .attr('width', width + margin.left + margin.right) @@ -148,21 +220,6 @@ function create (options) { .attr('stroke', '#89a19d'); } - if (currentDateMarker) { - const currentDate = new Date(); - - // Add a vertical red line for the current date - const currentX = xScale(currentDate); - svg.append('line') - .attr('x1', currentX) - .attr('x2', currentX) - .attr('stroke-width', 2) - .attr('y1', 0) - .attr('y2', height) - .attr('stroke', currentDateMarker) - .attr('opacity', 1); - } - svg.append('g') .attr('class', 'axis axis--x') .call(customXAxis); @@ -196,7 +253,7 @@ function create (options) { .attr('height', calculateHeight) .style('opacity', (data) => { // Hack to hide on current and unstable - if ((data.type === 'unstable' || data.type === 'current') || + if ((data.type === 'unstable' || data.type === 'current' || data.type === 'alpha') || xScale(data.start) <= 0) { return 0; } @@ -205,7 +262,7 @@ function create (options) { }); bar.append('text') - .attr('class', 'label') + .attr('class', data => data.type=== 'beta' ? 'label-beta' : 'label') .attr('x', (data) => { return xScale(data.start) + 15; }) @@ -226,6 +283,8 @@ function create (options) { if (typeof svgFile === 'string') { Fs.writeFileSync(svgFile, d3n.svgString()); + + console.log(`\n ![Release schedule proposal preview](.${svgFile.slice(svgFile.lastIndexOf('/'))})`) } if (typeof png === 'string') { diff --git a/lts.json b/lts.json index 69a967b..f59db08 100644 --- a/lts.json +++ b/lts.json @@ -1,53 +1,21 @@ { - "v0.10": { - "start": "2013-03-11", - "end": "2016-10-31" - }, - "v0.12": { - "start": "2015-02-06", - "end": "2016-12-31" - }, - "v4": { - "start": "2015-09-08", - "lts": "2015-10-12", - "maintenance": "2017-04-01", - "end": "2018-04-01", - "codename": "Argon" - }, - "v5": { - "start": "2015-10-29", - "maintenance": "2016-04-30", - "end": "2016-06-30" - }, - "v6": { - "start": "2016-04-26", - "lts": "2016-10-18", - "maintenance": "2018-04-01", - "end": "2019-04-01", - "codename": "Boron" - }, - "v7": { - "start": "2016-10-25", - "maintenance": "2017-04-30", - "end": "2017-06-30" - }, - "v8": { - "start": "2017-04-30", - "lts": "2017-10-31", - "maintenance": "2019-04-01", - "end": "2019-12-31", + "v24": { + "start": "2025-05-06", + "lts": "2025-10-28", + "maintenance": "2026-10-20", + "end": "2028-04-30", "codename": "" }, - "v9": { - "start": "2017-10-01", - "maintenance": "2018-04-01", - "end": "2018-06-30" + "v25": { + "start": "2025-10-15", + "maintenance": "2026-04-01", + "end": "2026-06-01" }, - "v10": { - "start": "2018-04-30", - "lts": "2018-10-01", - "maintenance": "2020-04-01", - "end": "2021-04-01", + "v26": { + "start": "2026-04-22", + "lts": "2026-10-20", + "maintenance": "2028-04-20", + "end": "2029-04-30", "codename": "" } } diff --git a/package.json b/package.json index 7829b90..6facaf3 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "node": ">=4.0.0" }, "dependencies": { + "@js-temporal/polyfill": "0.4.4", "bossy": "3.0.4", "d3": "4.7.4", "d3-node": "1.0.1", diff --git a/release-schedule-proposal/README.md b/release-schedule-proposal/README.md new file mode 100644 index 0000000..735a553 --- /dev/null +++ b/release-schedule-proposal/README.md @@ -0,0 +1,9 @@ +# Release schedule proposals + +To add a new proposal to this list, update the `schedule` variable in `lib/index.js`, and use the following command: + +```sh +node ./bin/lts.js -g release-schedule-proposal/.svg >> release-schedule-proposal/README.md +``` + +Here are the release schedule proposals: From 2ad8c4cf5a1d5a1bd830974ef38f2e27c6b0e613 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 13 Sep 2025 15:25:04 +0200 Subject: [PATCH 02/16] Add status quo --- bin/lts.js | 2 +- lib/index.js | 5 ++- release-schedule-proposal/README.md | 18 +++++++++ release-schedule-proposal/status-quo.svg | 40 ++++++++++++++++++++ release-schedule-proposal/status-quo2030.svg | 40 ++++++++++++++++++++ 5 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 release-schedule-proposal/status-quo.svg create mode 100644 release-schedule-proposal/status-quo2030.svg diff --git a/bin/lts.js b/bin/lts.js index 922eb1f..6593509 100644 --- a/bin/lts.js +++ b/bin/lts.js @@ -103,7 +103,7 @@ const options = { queryStart: new Date(args.start), queryEnd: new Date(args.end), html: args.html ? Path.resolve(args.html) : null, - svg: args.svg ? Path.resolve(args.svg) : null, + svg: args.svg ? Path.resolve(args.svg) : Path.join(__dirname, '..', 'release-schedule-proposal', 'status-quo.svg'), png: args.png ? Path.resolve(args.png) : null, animate: args.animate, excludeMain: args.excludeMain, diff --git a/lib/index.js b/lib/index.js index 356ceff..29aab02 100644 --- a/lib/index.js +++ b/lib/index.js @@ -46,7 +46,10 @@ const styles = ` }`; const schedule = { - // TODO + title: 'Status quo', + currentDuration: 'P6M', + activeDuration: ['P12M', false], + maintenanceDuration: ['P24M', 'P3M'], }; console.log(`\n## ${schedule.title}`); diff --git a/release-schedule-proposal/README.md b/release-schedule-proposal/README.md index 735a553..6ae2c6a 100644 --- a/release-schedule-proposal/README.md +++ b/release-schedule-proposal/README.md @@ -7,3 +7,21 @@ node ./bin/lts.js -g release-schedule-proposal/.svg >> release-s ``` Here are the release schedule proposals: + +## Status quo + + 1. current duration: 6 months + 2. active duration: + - for even-numbered releases: 12 months + - for odd-numbered releases: 0 months + 3. maintenance duration: + - for even-numbered releases: 24 months + - for odd-numbered releases: 3 months + + Total life span (from start of beta until end of maintenance): + - for even-numbered releases: 42 months + - for odd-numbered releases: 9 months + + ![Release schedule proposal preview](./status-quo.svg) + + ![Release schedule proposal preview](./status-quo2030.svg) diff --git a/release-schedule-proposal/status-quo.svg b/release-schedule-proposal/status-quo.svg new file mode 100644 index 0000000..8270d09 --- /dev/null +++ b/release-schedule-proposal/status-quo.svg @@ -0,0 +1,40 @@ +Jan26Jan27Jan28Jan29Jan30Jan31Jan32Jan33Jan34Jan35MainNode.js 24Node.js 25Node.js 26Node.js 27Node.js 28Node.js 29Node.js 30Node.js 31Node.js 32Node.js 33Node.js 34Node.js 35Node.js 36Node.js 37Node.js 38Node.js 39Node.js 40Node.js 41Node.js 42Node.js 43unstablemaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentactivecurrentcurrent \ No newline at end of file diff --git a/release-schedule-proposal/status-quo2030.svg b/release-schedule-proposal/status-quo2030.svg new file mode 100644 index 0000000..6a93dbd --- /dev/null +++ b/release-schedule-proposal/status-quo2030.svg @@ -0,0 +1,40 @@ +Oct29Jan30Apr30Jul30Oct30Jan31Apr31MainNode.js 28Node.js 30Node.js 32Node.js 33Node.js 34Node.js 35Node.js 36unstablemaintenancemaintenanceactivemaintenanceactivecurrentmaintenancecurrentactivecurrentmaintenancecurrentcurrent \ No newline at end of file From 587e68a7fae4cb124a24782d74d130abc91b7481 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 13 Sep 2025 15:26:53 +0200 Subject: [PATCH 03/16] release schedule proposal: LTS every year alphaDuration: 'P5M', betaDuration: 'P1M', currentDuration: 'P6M', activeDuration: 'P12M', maintenanceDuration: 'P18M', --- bin/lts.js | 2 +- lib/index.js | 10 +++-- release-schedule-proposal/README.md | 14 +++++++ release-schedule-proposal/lts-every-year.svg | 40 +++++++++++++++++++ .../lts-every-year2030.svg | 40 +++++++++++++++++++ 5 files changed, 101 insertions(+), 5 deletions(-) create mode 100644 release-schedule-proposal/lts-every-year.svg create mode 100644 release-schedule-proposal/lts-every-year2030.svg diff --git a/bin/lts.js b/bin/lts.js index 6593509..a2d63b6 100644 --- a/bin/lts.js +++ b/bin/lts.js @@ -103,7 +103,7 @@ const options = { queryStart: new Date(args.start), queryEnd: new Date(args.end), html: args.html ? Path.resolve(args.html) : null, - svg: args.svg ? Path.resolve(args.svg) : Path.join(__dirname, '..', 'release-schedule-proposal', 'status-quo.svg'), + svg: args.svg ? Path.resolve(args.svg) : Path.join(__dirname, '..', 'release-schedule-proposal', 'lts-every-year.svg'), png: args.png ? Path.resolve(args.png) : null, animate: args.animate, excludeMain: args.excludeMain, diff --git a/lib/index.js b/lib/index.js index 29aab02..54cdc49 100644 --- a/lib/index.js +++ b/lib/index.js @@ -46,11 +46,13 @@ const styles = ` }`; const schedule = { - title: 'Status quo', - currentDuration: 'P6M', - activeDuration: ['P12M', false], - maintenanceDuration: ['P24M', 'P3M'], + title: 'LTS every year', + alphaDuration: { months: 5 }, + betaDuration: { months: 1 }, + currentDuration: { months: 6 }, + activeDuration: { months: 12 }, }; +schedule.maintenanceDuration = { months: schedule.currentDuration.months + schedule.activeDuration.months }; console.log(`\n## ${schedule.title}`); { diff --git a/release-schedule-proposal/README.md b/release-schedule-proposal/README.md index 6ae2c6a..0d6d9a2 100644 --- a/release-schedule-proposal/README.md +++ b/release-schedule-proposal/README.md @@ -25,3 +25,17 @@ Here are the release schedule proposals: ![Release schedule proposal preview](./status-quo.svg) ![Release schedule proposal preview](./status-quo2030.svg) + +## LTS every year + + 1. alpha duration: 5 months + 2. beta duration: 1 months + 3. current duration: 6 months + 4. active duration: 12 months + 5. maintenance duration: 18 months + + Total life span (from start of beta until end of maintenance): 37 months + + ![Release schedule proposal preview](./lts-every-year.svg) + + ![Release schedule proposal preview](./lts-every-year2030.svg) diff --git a/release-schedule-proposal/lts-every-year.svg b/release-schedule-proposal/lts-every-year.svg new file mode 100644 index 0000000..cf4c553 --- /dev/null +++ b/release-schedule-proposal/lts-every-year.svg @@ -0,0 +1,40 @@ +Jan26Jan27Jan28Jan29Jan30Jan31Jan32Jan33Jan34Jan35MainNode.js 24Node.js 25Node.js 26Node.js 27Node.js 28Node.js 29Node.js 30Node.js 31Node.js 32Node.js 33Node.js 34Node.js 35unstablemaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenanceactivecurrentbetaalphamaintenanceactivecurrentbetaalphamaintenanceactivecurrentbetaalphamaintenanceactivecurrentbetaalphamaintenanceactivecurrentbetaalphamaintenanceactivecurrentbetaalphamaintenanceactivecurrentbetaalphaactivecurrentbetaalphabetaalpha \ No newline at end of file diff --git a/release-schedule-proposal/lts-every-year2030.svg b/release-schedule-proposal/lts-every-year2030.svg new file mode 100644 index 0000000..fe84cae --- /dev/null +++ b/release-schedule-proposal/lts-every-year2030.svg @@ -0,0 +1,40 @@ +Oct29Jan30Apr30Jul30Oct30Jan31Apr31MainNode.js 27Node.js 28Node.js 29Node.js 30Node.js 31unstablemaintenancebetaalphamaintenanceactivebetaalphamaintenanceactivecurrentbetaalphaactivecurrentbetaalphacurrentbetaalpha \ No newline at end of file From cae8acd2875c2328fb3961ece5c5283cdba67245 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 13 Sep 2025 15:33:43 +0200 Subject: [PATCH 04/16] release schedule proposal: longer life cycle currentDuration: ['P6M', 'P12M'], activeDuration: ['P18M', false], maintenanceDuration: ['P24M', 'P2M'], --- bin/lts.js | 2 +- lib/index.js | 13 +++--- release-schedule-proposal/README.md | 20 ++++++++++ .../longer-life-cycle.svg | 40 +++++++++++++++++++ .../longer-life-cycle2030.svg | 40 +++++++++++++++++++ 5 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 release-schedule-proposal/longer-life-cycle.svg create mode 100644 release-schedule-proposal/longer-life-cycle2030.svg diff --git a/bin/lts.js b/bin/lts.js index a2d63b6..d384fee 100644 --- a/bin/lts.js +++ b/bin/lts.js @@ -103,7 +103,7 @@ const options = { queryStart: new Date(args.start), queryEnd: new Date(args.end), html: args.html ? Path.resolve(args.html) : null, - svg: args.svg ? Path.resolve(args.svg) : Path.join(__dirname, '..', 'release-schedule-proposal', 'lts-every-year.svg'), + svg: args.svg ? Path.resolve(args.svg) : Path.join(__dirname, '..', 'release-schedule-proposal', 'longer-life-cycle.svg'), png: args.png ? Path.resolve(args.png) : null, animate: args.animate, excludeMain: args.excludeMain, diff --git a/lib/index.js b/lib/index.js index 54cdc49..cafb188 100644 --- a/lib/index.js +++ b/lib/index.js @@ -46,13 +46,14 @@ const styles = ` }`; const schedule = { - title: 'LTS every year', - alphaDuration: { months: 5 }, - betaDuration: { months: 1 }, - currentDuration: { months: 6 }, - activeDuration: { months: 12 }, + title: 'Longer life cycle', + currentDuration: [{ months: 6 }, { months: 12 }], + activeDuration: [{ months: 18 }, false], }; -schedule.maintenanceDuration = { months: schedule.currentDuration.months + schedule.activeDuration.months }; +schedule.maintenanceDuration = [ + { months: schedule.currentDuration[0].months + schedule.currentDuration[0].active }, + { months: 2 }, +]; console.log(`\n## ${schedule.title}`); { diff --git a/release-schedule-proposal/README.md b/release-schedule-proposal/README.md index 0d6d9a2..e23b996 100644 --- a/release-schedule-proposal/README.md +++ b/release-schedule-proposal/README.md @@ -39,3 +39,23 @@ Here are the release schedule proposals: ![Release schedule proposal preview](./lts-every-year.svg) ![Release schedule proposal preview](./lts-every-year2030.svg) + +## Longer life cycle + + 1. current duration: + - for even-numbered releases: 6 months + - for odd-numbered releases: 12 months + 2. active duration: + - for even-numbered releases: 18 months + - for odd-numbered releases: 0 months + 3. maintenance duration: + - for even-numbered releases: 24 months + - for odd-numbered releases: 2 months + + Total life span (from start of beta until end of maintenance): + - for even-numbered releases: 48 months + - for odd-numbered releases: 14 months + + ![Release schedule proposal preview](./longer-life-cycle.svg) + + ![Release schedule proposal preview](./longer-life-cycle2030.svg) diff --git a/release-schedule-proposal/longer-life-cycle.svg b/release-schedule-proposal/longer-life-cycle.svg new file mode 100644 index 0000000..a98ed11 --- /dev/null +++ b/release-schedule-proposal/longer-life-cycle.svg @@ -0,0 +1,40 @@ +Jan26Jan27Jan28Jan29Jan30Jan31Jan32Jan33Jan34Jan35MainNode.js 24Node.js 25Node.js 26Node.js 27Node.js 28Node.js 29Node.js 30Node.js 31Node.js 32Node.js 33Node.js 34Node.js 35Node.js 36Node.js 37unstablemaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentactivecurrentcurrent \ No newline at end of file diff --git a/release-schedule-proposal/longer-life-cycle2030.svg b/release-schedule-proposal/longer-life-cycle2030.svg new file mode 100644 index 0000000..73622ef --- /dev/null +++ b/release-schedule-proposal/longer-life-cycle2030.svg @@ -0,0 +1,40 @@ +Oct29Jan30Apr30Jul30Oct30Jan31Apr31MainNode.js 28Node.js 30Node.js 31Node.js 32Node.js 33unstablemaintenanceactivemaintenanceactivecurrentmaintenancecurrentactivecurrentcurrent \ No newline at end of file From 22fa11ef0b7d85fa712bc3f0bafa51a303488e64 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 13 Sep 2025 15:38:20 +0200 Subject: [PATCH 05/16] release schedule proposal: less frequent LTS currentDuration: 'P6M', activeDuration: ['P24M', false, false, false], maintenanceDuration: ['P18M', 'P2M', 'P2M', 'P2M'], --- bin/lts.js | 2 +- lib/index.js | 12 +++--- release-schedule-proposal/README.md | 18 +++++++++ .../less-frequent-lts.svg | 40 +++++++++++++++++++ .../less-frequent-lts2030.svg | 40 +++++++++++++++++++ 5 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 release-schedule-proposal/less-frequent-lts.svg create mode 100644 release-schedule-proposal/less-frequent-lts2030.svg diff --git a/bin/lts.js b/bin/lts.js index d384fee..87071c8 100644 --- a/bin/lts.js +++ b/bin/lts.js @@ -103,7 +103,7 @@ const options = { queryStart: new Date(args.start), queryEnd: new Date(args.end), html: args.html ? Path.resolve(args.html) : null, - svg: args.svg ? Path.resolve(args.svg) : Path.join(__dirname, '..', 'release-schedule-proposal', 'longer-life-cycle.svg'), + svg: args.svg ? Path.resolve(args.svg) : Path.join(__dirname, '..', 'release-schedule-proposal', 'less-frequent-lts.svg'), png: args.png ? Path.resolve(args.png) : null, animate: args.animate, excludeMain: args.excludeMain, diff --git a/lib/index.js b/lib/index.js index cafb188..daf26d8 100644 --- a/lib/index.js +++ b/lib/index.js @@ -46,14 +46,14 @@ const styles = ` }`; const schedule = { - title: 'Longer life cycle', - currentDuration: [{ months: 6 }, { months: 12 }], - activeDuration: [{ months: 18 }, false], + title: 'Less frequent LTS', + currentDuration: { months: 6 }, + activeDuration: [{ months: 24 }, false, false, false], }; schedule.maintenanceDuration = [ - { months: schedule.currentDuration[0].months + schedule.currentDuration[0].active }, - { months: 2 }, -]; + { months: schedule.currentDuration.months * 3 }, + { months: 2 }, { months: 2 }, { months: 2 }, +] console.log(`\n## ${schedule.title}`); { diff --git a/release-schedule-proposal/README.md b/release-schedule-proposal/README.md index e23b996..10494e1 100644 --- a/release-schedule-proposal/README.md +++ b/release-schedule-proposal/README.md @@ -59,3 +59,21 @@ Here are the release schedule proposals: ![Release schedule proposal preview](./longer-life-cycle.svg) ![Release schedule proposal preview](./longer-life-cycle2030.svg) + +## Less frequent LTS + + 1. current duration: 6 months + 2. active duration: + - for modulo-4-numbered releases: 24 months + - for other releases: 0 months + 3. maintenance duration: + - for modulo-4-numbered releases: 18 months + - for other releases: 2 months + + Total life span (from start of beta until end of maintenance): + - for module-4-numbered releases: 48 months + - for releases: 8 months + + ![Release schedule proposal preview](./less-frequent-lts.svg) + + ![Release schedule proposal preview](./less-frequent-lts2030.svg) diff --git a/release-schedule-proposal/less-frequent-lts.svg b/release-schedule-proposal/less-frequent-lts.svg new file mode 100644 index 0000000..fffdc9f --- /dev/null +++ b/release-schedule-proposal/less-frequent-lts.svg @@ -0,0 +1,40 @@ +Jan26Jan27Jan28Jan29Jan30Jan31Jan32Jan33Jan34Jan35MainNode.js 24Node.js 25Node.js 26Node.js 27Node.js 28Node.js 29Node.js 30Node.js 31Node.js 32Node.js 33Node.js 34Node.js 35Node.js 36Node.js 37Node.js 38Node.js 39Node.js 40Node.js 41Node.js 42Node.js 43unstablemaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentactivecurrentmaintenancecurrentmaintenancecurrentcurrent \ No newline at end of file diff --git a/release-schedule-proposal/less-frequent-lts2030.svg b/release-schedule-proposal/less-frequent-lts2030.svg new file mode 100644 index 0000000..e1664b7 --- /dev/null +++ b/release-schedule-proposal/less-frequent-lts2030.svg @@ -0,0 +1,40 @@ +Oct29Jan30Apr30Jul30Oct30Jan31Apr31MainNode.js 28Node.js 32Node.js 33Node.js 34Node.js 35Node.js 36unstablemaintenanceactiveactivecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentcurrent \ No newline at end of file From c39601c901c38e1b64b14dd520d28fe3551ea500 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 13 Sep 2025 18:25:23 +0200 Subject: [PATCH 06/16] release schedule proposal: no Active LTS anymore currentDuration: 'P12M', activeDuration: false, maintenanceDuration: 'P18M', --- bin/lts.js | 2 +- lib/index.js | 11 ++--- release-schedule-proposal/README.md | 12 ++++++ release-schedule-proposal/no-active-lts.svg | 40 +++++++++++++++++++ .../no-active-lts2030.svg | 40 +++++++++++++++++++ 5 files changed, 97 insertions(+), 8 deletions(-) create mode 100644 release-schedule-proposal/no-active-lts.svg create mode 100644 release-schedule-proposal/no-active-lts2030.svg diff --git a/bin/lts.js b/bin/lts.js index 87071c8..c659d4a 100644 --- a/bin/lts.js +++ b/bin/lts.js @@ -103,7 +103,7 @@ const options = { queryStart: new Date(args.start), queryEnd: new Date(args.end), html: args.html ? Path.resolve(args.html) : null, - svg: args.svg ? Path.resolve(args.svg) : Path.join(__dirname, '..', 'release-schedule-proposal', 'less-frequent-lts.svg'), + svg: args.svg ? Path.resolve(args.svg) : Path.join(__dirname, '..', 'release-schedule-proposal', 'no-active-lts.svg'), png: args.png ? Path.resolve(args.png) : null, animate: args.animate, excludeMain: args.excludeMain, diff --git a/lib/index.js b/lib/index.js index daf26d8..0cdc6ba 100644 --- a/lib/index.js +++ b/lib/index.js @@ -46,14 +46,11 @@ const styles = ` }`; const schedule = { - title: 'Less frequent LTS', - currentDuration: { months: 6 }, - activeDuration: [{ months: 24 }, false, false, false], + title: 'No Active LTS anymore', + currentDuration: { months: 12 }, + activeDuration: false, }; -schedule.maintenanceDuration = [ - { months: schedule.currentDuration.months * 3 }, - { months: 2 }, { months: 2 }, { months: 2 }, -] +schedule.maintenanceDuration= { months: schedule.currentDuration.months * 2 }; console.log(`\n## ${schedule.title}`); { diff --git a/release-schedule-proposal/README.md b/release-schedule-proposal/README.md index 10494e1..0454933 100644 --- a/release-schedule-proposal/README.md +++ b/release-schedule-proposal/README.md @@ -77,3 +77,15 @@ Here are the release schedule proposals: ![Release schedule proposal preview](./less-frequent-lts.svg) ![Release schedule proposal preview](./less-frequent-lts2030.svg) + +## No Active LTS anymore + + 1. current duration: 12 months + 2. active duration: 0 months + 3. maintenance duration: 24 months + + Total life span (from start of beta until end of maintenance): 36 months + + ![Release schedule proposal preview](./no-active-lts.svg) + + ![Release schedule proposal preview](./no-active-lts2030.svg) diff --git a/release-schedule-proposal/no-active-lts.svg b/release-schedule-proposal/no-active-lts.svg new file mode 100644 index 0000000..4594175 --- /dev/null +++ b/release-schedule-proposal/no-active-lts.svg @@ -0,0 +1,40 @@ +Jan26Jan27Jan28Jan29Jan30Jan31Jan32Jan33Jan34Jan35MainNode.js 24Node.js 25Node.js 26Node.js 27Node.js 28Node.js 29Node.js 30Node.js 31Node.js 32Node.js 33Node.js 34Node.js 35unstablemaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentcurrent \ No newline at end of file diff --git a/release-schedule-proposal/no-active-lts2030.svg b/release-schedule-proposal/no-active-lts2030.svg new file mode 100644 index 0000000..f7ce0ca --- /dev/null +++ b/release-schedule-proposal/no-active-lts2030.svg @@ -0,0 +1,40 @@ +Oct29Jan30Apr30Jul30Oct30Jan31Apr31MainNode.js 27Node.js 28Node.js 29Node.js 30Node.js 31unstablemaintenancemaintenancemaintenancecurrentmaintenancecurrentcurrent \ No newline at end of file From cd0aafdf01cd0afa1490134347cf20555da9ea7c Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 20 Sep 2025 14:04:30 +0200 Subject: [PATCH 07/16] Update "LTS every year" section with tentative release schedule Added tentative release schedule for version 27.0.0 and related changes. --- release-schedule-proposal/README.md | 31 +++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/release-schedule-proposal/README.md b/release-schedule-proposal/README.md index 0454933..8c99f91 100644 --- a/release-schedule-proposal/README.md +++ b/release-schedule-proposal/README.md @@ -40,6 +40,37 @@ Here are the release schedule proposals: ![Release schedule proposal preview](./lts-every-year2030.svg) +Version | Tentative Date | Type of changes +--------|--------------| ------------- +v27.0.0-alpha.0 | 2026-10-20 | Branch-off +v27.0.0-alpha.1 | 2026-11-03 | most changes[^1] +v27.0.0-alpha.2 | 2026-11-17 | most changes[^1] +v27.0.0-alpha.3 | 2026-12-01 | most changes[^1] +v27.0.0-alpha.4 | 2026-12-15 | most changes[^1] +v27.0.0-alpha.5 | 2026-12-29 | most changes[^1] +v27.0.0-alpha.6 | 2027-01-12 | most changes[^1] +v27.0.0-alpha.7 | 2027-01-26 | most changes[^1] +v27.0.0-alpha.8 | 2027-02-09 | most changes[^1] +v27.0.0-alpha.9 | 2027-02-23 | most changes[^1] +v27.0.0-alpha.10 | 2027-03-09 | most changes[^1] +v27.0.0-beta.0 | 2027-03-23 | most changes[^1] + V8 update[^2] +v27.0.0-beta.1 | 2027-04-06 | semver-minor only + V8 update[^2] +v27.0.0 | 2027-04-20 | semver-minor only +v27.x.x | 2027-05-04 | … +v27.x.x | 2027-10-05 | … +v27.x.x (LTS transition) | 2027-10-20 | +(Maintenance transition) | 2028-10-20 | _No release_ +(End-of-Life) | 2030-10-20 | _No release_ + +**Security support**: It has not been decided whether security fixes would +trigger a security release, or if those would simply be included in the next +regular release (potentially ahead of schedule). The difference on a maintenance +perspective is that a security release requires locking the CI until all the +queued security releases are ready. + +[^1]: Most changes from `main`, except those marked as `dont-land-on-v27.x` because they contain ABI-breaking changes or e.g. are moving a deprecation to EOL if 27.x already contains the change moving it to Runtime. +[^2]: V8 update are (typically) ABI-breaking, however it is considered worth doing given otherwise the V8 version included would be 1 year old by the time the release line transitions to LTS. + ## Longer life cycle 1. current duration: From 42258a7a6fe3204cc2bada9b990a97d7ba91b6b2 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 20 Sep 2025 14:31:20 +0200 Subject: [PATCH 08/16] Enhance "LTS every year" section Added definitions for Alpha and Beta phases, including stability expectations and release frequency details. --- release-schedule-proposal/README.md | 48 +++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/release-schedule-proposal/README.md b/release-schedule-proposal/README.md index 8c99f91..2388ce2 100644 --- a/release-schedule-proposal/README.md +++ b/release-schedule-proposal/README.md @@ -28,11 +28,11 @@ Here are the release schedule proposals: ## LTS every year - 1. alpha duration: 5 months - 2. beta duration: 1 months - 3. current duration: 6 months - 4. active duration: 12 months - 5. maintenance duration: 18 months + 1. Alpha duration: 5 months + 2. Beta duration: 1 months + 3. Current duration: 6 months + 4. Active duration: 12 months + 5. Maintenance duration: 18 months Total life span (from start of beta until end of maintenance): 37 months @@ -40,6 +40,25 @@ Here are the release schedule proposals: ![Release schedule proposal preview](./lts-every-year2030.svg) +### Alpha and Beta definition + +#### Stability expectations + +Alpha releases may contain semver-major changes (assuming such change does not "break the ecosystem"), but no ABI-breaking changes (so native addons can be tested on those versions). + +Once the release has reached the beta period, semver-major changes will no +longer be included, except: + +- security fixes +- V8 update +- one-time exception granted by the TSC + +Updating V8 during the Beta period is considered the optimal tradeoff, despite +the ABI and API potential breakage, as otherwise the included V8 version would +be 1 year old by the time the release line transitions to LTS. + +#### Release frequency + Version | Tentative Date | Type of changes --------|--------------| ------------- v27.0.0-alpha.0 | 2026-10-20 | Branch-off @@ -53,24 +72,27 @@ v27.0.0-alpha.7 | 2027-01-26 | most changes[^1] v27.0.0-alpha.8 | 2027-02-09 | most changes[^1] v27.0.0-alpha.9 | 2027-02-23 | most changes[^1] v27.0.0-alpha.10 | 2027-03-09 | most changes[^1] -v27.0.0-beta.0 | 2027-03-23 | most changes[^1] + V8 update[^2] -v27.0.0-beta.1 | 2027-04-06 | semver-minor only + V8 update[^2] +v27.0.0-beta.0 | 2027-03-23 | most changes[^1] + V8 update +v27.0.0-beta.1 | 2027-04-06 | semver-minor only + V8 update v27.0.0 | 2027-04-20 | semver-minor only v27.x.x | 2027-05-04 | … v27.x.x | 2027-10-05 | … v27.x.x (LTS transition) | 2027-10-20 | -(Maintenance transition) | 2028-10-20 | _No release_ -(End-of-Life) | 2030-10-20 | _No release_ +(Maintenance transition) | 2028-10-20 | +(End-of-Life) | 2030-10-20 | + +[^1]: Most changes from `main`, except those marked as `dont-land-on-v27.x` because e.g. they contain ABI-breaking changes, or are considered too breaking for the ecosystem, or are moving a deprecation to EOL if 27.x already contains the change moving it to Runtime. + +#### Security support -**Security support**: It has not been decided whether security fixes would +TL;DR: TBD + +It has not been decided whether security fixes would trigger a security release, or if those would simply be included in the next regular release (potentially ahead of schedule). The difference on a maintenance perspective is that a security release requires locking the CI until all the queued security releases are ready. -[^1]: Most changes from `main`, except those marked as `dont-land-on-v27.x` because they contain ABI-breaking changes or e.g. are moving a deprecation to EOL if 27.x already contains the change moving it to Runtime. -[^2]: V8 update are (typically) ABI-breaking, however it is considered worth doing given otherwise the V8 version included would be 1 year old by the time the release line transitions to LTS. - ## Longer life cycle 1. current duration: From 18bbdd4f70c16a7fd38ce508f575e93f803b0cb3 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Tue, 23 Sep 2025 13:56:17 +0200 Subject: [PATCH 09/16] Revise README for proposal submission and release schedule Updated instructions for adding proposals and clarified release schedule details. --- release-schedule-proposal/README.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/release-schedule-proposal/README.md b/release-schedule-proposal/README.md index 2388ce2..0d1e614 100644 --- a/release-schedule-proposal/README.md +++ b/release-schedule-proposal/README.md @@ -1,9 +1,10 @@ # Release schedule proposals -To add a new proposal to this list, update the `schedule` variable in `lib/index.js`, and use the following command: +To add a new proposal to this list, update the `schedule` variable in `lib/index.js`, +the SVG name in `bin/lts.js`, and use the following command: ```sh -node ./bin/lts.js -g release-schedule-proposal/.svg >> release-schedule-proposal/README.md +node ./bin/lts.js >> release-schedule-proposal/README.md ``` Here are the release schedule proposals: @@ -44,7 +45,8 @@ Here are the release schedule proposals: #### Stability expectations -Alpha releases may contain semver-major changes (assuming such change does not "break the ecosystem"), but no ABI-breaking changes (so native addons can be tested on those versions). +Alpha releases may contain semver-major changes (assuming such change does not "break the ecosystem"), +but no ABI-breaking changes (so native addons can be tested on those versions). Once the release has reached the beta period, semver-major changes will no longer be included, except: @@ -53,6 +55,9 @@ longer be included, except: - V8 update - one-time exception granted by the TSC +Once the beta period is ended, only security fixes and one-time exception +granted by the TSC may contain semver-major changes. + Updating V8 during the Beta period is considered the optimal tradeoff, despite the ABI and API potential breakage, as otherwise the included V8 version would be 1 year old by the time the release line transitions to LTS. @@ -77,9 +82,9 @@ v27.0.0-beta.1 | 2027-04-06 | semver-minor only + V8 update v27.0.0 | 2027-04-20 | semver-minor only v27.x.x | 2027-05-04 | … v27.x.x | 2027-10-05 | … -v27.x.x (LTS transition) | 2027-10-20 | -(Maintenance transition) | 2028-10-20 | -(End-of-Life) | 2030-10-20 | +v27.x.x (LTS transition) | 2027-10-20 | no changes +(Maintenance transition) | 2028-10-20 | _No release_ +(End-of-Life) | 2030-10-20 | _No release_ [^1]: Most changes from `main`, except those marked as `dont-land-on-v27.x` because e.g. they contain ABI-breaking changes, or are considered too breaking for the ecosystem, or are moving a deprecation to EOL if 27.x already contains the change moving it to Runtime. From 01fefb6e601f73abe41f56e2786157ab1b27d562 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 25 Sep 2025 01:16:27 +0200 Subject: [PATCH 10/16] add rolling semver-major proposal --- bin/lts.js | 2 +- lib/index.js | 20 +++++++----- release-schedule-proposal/README.md | 18 ++++++++++ release-schedule-proposal/rolling.svg | 40 +++++++++++++++++++++++ release-schedule-proposal/rolling2030.svg | 40 +++++++++++++++++++++++ 5 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 release-schedule-proposal/rolling.svg create mode 100644 release-schedule-proposal/rolling2030.svg diff --git a/bin/lts.js b/bin/lts.js index c659d4a..e5fca0c 100644 --- a/bin/lts.js +++ b/bin/lts.js @@ -103,7 +103,7 @@ const options = { queryStart: new Date(args.start), queryEnd: new Date(args.end), html: args.html ? Path.resolve(args.html) : null, - svg: args.svg ? Path.resolve(args.svg) : Path.join(__dirname, '..', 'release-schedule-proposal', 'no-active-lts.svg'), + svg: args.svg ? Path.resolve(args.svg) : Path.join(__dirname, '..', 'release-schedule-proposal', 'rolling.svg'), png: args.png ? Path.resolve(args.png) : null, animate: args.animate, excludeMain: args.excludeMain, diff --git a/lib/index.js b/lib/index.js index 0cdc6ba..6996c54 100644 --- a/lib/index.js +++ b/lib/index.js @@ -46,17 +46,17 @@ const styles = ` }`; const schedule = { - title: 'No Active LTS anymore', - currentDuration: { months: 12 }, + title: 'Rolling semver-major', + currentDuration: { weeks: 6 }, + maintenanceDuration: { weeks: 8 }, activeDuration: false, }; -schedule.maintenanceDuration= { months: schedule.currentDuration.months * 2 }; console.log(`\n## ${schedule.title}`); { const ___ = duration_s => Array.isArray(duration_s) ? `\n - for even-numbered releases:${___(duration_s[0])}\n - for odd-numbered releases:${___(duration_s[1])}` : - ` ${duration_s ? Temporal.Duration.from(duration_s).months : 0} months`; + ` ${duration_s ? Temporal.Duration.from(duration_s).weeks : 0} weeks`; console.log(Object.entries(schedule).map(([key, duration], i) => key === 'title' ? '' : ` ${i}. ${key.replace('D', ' d')}:${___(duration)}` ).join('\n')); @@ -64,10 +64,10 @@ console.log(`\n## ${schedule.title}`); { const durations = Object.entries(schedule).filter(c => c[0] !== 'title' && c[0] !== 'alphaDuration' && c[1]).map(c => c[1]); const hasArray = durations.some(Array.isArray); - const __ = arr => arr.reduce((acc, dur) => acc+Temporal.Duration.from(dur).months, 0) + const __ = arr => arr.reduce((acc, dur) => acc+Temporal.Duration.from(dur).weeks, 0) const ___ = () => hasArray ? - `\n - for even-numbered releases: ${__(durations.map(c => (Array.isArray(c) ? c[0] : c) || 'P0M'))} months\n - for odd-numbered releases: ${__(durations.map(c => (Array.isArray(c) ? c[1] : c) || 'P0M'))} months` : - ` ${__(durations)} months`; + `\n - for even-numbered releases: ${__(durations.map(c => (Array.isArray(c) ? c[0] : c) || 'P0M'))} weeks\n - for odd-numbered releases: ${__(durations.map(c => (Array.isArray(c) ? c[1] : c) || 'P0M'))} weeks` : + ` ${__(durations)} weeks`; console.log(`\n Total life span (from start of beta until end of maintenance):${___(schedule)}`) } @@ -76,11 +76,13 @@ const __ = (duration_s, i) => Array.isArray(duration_s) ? duration_s[i % duratio function createDataEntry(start, i) { const ret = {}; + const isLTS = (start.month === 10 && start.year !== 2026) || (start.month === 9 && start.day > 17); + const alphaDuration = __(schedule.alphaDuration, i); const betaDuration = __(schedule.betaDuration, i); const currentDuration = __(schedule.currentDuration, i); - const activeDuration = __(schedule.activeDuration, i); - const maintenanceDuration = __(schedule.maintenanceDuration, i); + const activeDuration = __(isLTS ? { months: 12} : schedule.activeDuration, i); + const maintenanceDuration = __(isLTS ? {months: 18} : schedule.maintenanceDuration, i); if (alphaDuration) { ret.alpha = start.toString(); diff --git a/release-schedule-proposal/README.md b/release-schedule-proposal/README.md index 0d1e614..f33846a 100644 --- a/release-schedule-proposal/README.md +++ b/release-schedule-proposal/README.md @@ -147,3 +147,21 @@ queued security releases are ready. ![Release schedule proposal preview](./no-active-lts.svg) ![Release schedule proposal preview](./no-active-lts2030.svg) + +## Rolling semver-major + + 1. current duration: 6 weeks + 3. active duration: + - 0 weeks + - or 12 months for the October release + 2. maintenance duration: + - 8 weeks + - or 18 months for the October release + + Total life span (from start of beta until end of maintenance): + - 14 weeks + - or 31 months for the October release + + ![Release schedule proposal preview](./rolling.svg) + + ![Release schedule proposal preview](./rolling2030.svg) diff --git a/release-schedule-proposal/rolling.svg b/release-schedule-proposal/rolling.svg new file mode 100644 index 0000000..28d8c7f --- /dev/null +++ b/release-schedule-proposal/rolling.svg @@ -0,0 +1,40 @@ +Jan26Jan27Jan28Jan29Jan30Jan31Jan32Jan33Jan34Jan35MainNode.js 24Node.js 25Node.js 26Node.js 27Node.js 28Node.js 29Node.js 30Node.js 31Node.js 32Node.js 33Node.js 34Node.js 35Node.js 36Node.js 37Node.js 38Node.js 39Node.js 40Node.js 41Node.js 42Node.js 43Node.js 44Node.js 45Node.js 46Node.js 47Node.js 48Node.js 49Node.js 50Node.js 51Node.js 52Node.js 53Node.js 54Node.js 55Node.js 56Node.js 57Node.js 58Node.js 59Node.js 60Node.js 61Node.js 62Node.js 63Node.js 64Node.js 65Node.js 66Node.js 67Node.js 68Node.js 69Node.js 70Node.js 71Node.js 72Node.js 73Node.js 74Node.js 75Node.js 76Node.js 77Node.js 78Node.js 79Node.js 80Node.js 81Node.js 82Node.js 83Node.js 84Node.js 85Node.js 86Node.js 87Node.js 88Node.js 89Node.js 90Node.js 91Node.js 92Node.js 93Node.js 94Node.js 95Node.js 96Node.js 97Node.js 98unstablemaintenanceactivecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentactivecurrentmaintenancecurrentcurrent \ No newline at end of file diff --git a/release-schedule-proposal/rolling2030.svg b/release-schedule-proposal/rolling2030.svg new file mode 100644 index 0000000..8e32392 --- /dev/null +++ b/release-schedule-proposal/rolling2030.svg @@ -0,0 +1,40 @@ +Oct29Jan30Apr30Jul30Oct30Jan31Apr31MainNode.js 35Node.js 44Node.js 50Node.js 51Node.js 52Node.js 53Node.js 54Node.js 55Node.js 56Node.js 57Node.js 58Node.js 59Node.js 60Node.js 61Node.js 62Node.js 63Node.js 64Node.js 65Node.js 66unstablemaintenancemaintenanceactivemaintenancemaintenancecurrentmaintenancecurrentmaintenanceactivecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentactivecurrentmaintenancecurrentmaintenancecurrentmaintenancecurrentcurrent \ No newline at end of file From de6d70b838273245171a79ef8c0c05e8ef07508c Mon Sep 17 00:00:00 2001 From: RafaelGSS Date: Thu, 16 Oct 2025 14:33:11 -0300 Subject: [PATCH 11/16] apply Richard's comments --- release-schedule-proposal/README.md | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/release-schedule-proposal/README.md b/release-schedule-proposal/README.md index f33846a..0947470 100644 --- a/release-schedule-proposal/README.md +++ b/release-schedule-proposal/README.md @@ -7,6 +7,27 @@ the SVG name in `bin/lts.js`, and use the following command: node ./bin/lts.js >> release-schedule-proposal/README.md ``` +## Enterprise Feedback + +* Current releases are generally ignored (including the even-numbered releases). +* Prefer to keep (i.e. do not shorten) 30 month LTS support window (from start of Active LTS through to End-of-Life). +* Several teams asked if the LTS support window could be extended (5 years was quoted for other software (e.g. OpenSSL) LTS). +* Want predictable cadence for forward planning. +* Want LTS support window overlap to aid migration from one LTS release line to another. + +## Dependency lifecycles + +| Dependency | LTS policy | Notes | +|-|-|-| +| c-ares | Unknown | - | +| ICU4C | Unknown | Releases historically appear to be April and October. We have generally updated within release lines as ICU does not consider changes to localized output to be breaking, but we have had issues raised against Node.js when output changes | +| libuv | None | Has historically accommodated Node.js due to overlap of collaborators/maintainers | +| npm | None | https://github.com/npm/cli/wiki/Integrating-with-node | +| OpenSSL | [Policy](https://openssl-library.org/policies/releasestrat/index.html). New LTS every 2 years. Each LTS supported minimum of 5 years. | "In essence that means an LTS will be released every April in odd-numbered years." so may just miss new LTS versions for Node.js semver-majors if we keep to April releases | +| Undici | Unknown | Overlap of collaborators/maintainers with Node.js | +| V8 | None. Does not follow semver. | V8 updates are generally considered semver-major as the V8 ABI is part of Node.js' | +| zlib | Unknown | Node.js is using Chromium's fork of zlib | + Here are the release schedule proposals: ## Status quo @@ -16,11 +37,11 @@ Here are the release schedule proposals: - for even-numbered releases: 12 months - for odd-numbered releases: 0 months 3. maintenance duration: - - for even-numbered releases: 24 months + - for even-numbered releases: 18 months - for odd-numbered releases: 3 months Total life span (from start of beta until end of maintenance): - - for even-numbered releases: 42 months + - for even-numbered releases: 36 months - for odd-numbered releases: 9 months ![Release schedule proposal preview](./status-quo.svg) From c94daf42bd187ef82fb74ec92d98bf7061ca9fe6 Mon Sep 17 00:00:00 2001 From: RafaelGSS Date: Thu, 16 Oct 2025 15:25:35 -0300 Subject: [PATCH 12/16] Add Rafael thought's on maintainers feedback --- release-schedule-proposal/README.md | 33 ++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/release-schedule-proposal/README.md b/release-schedule-proposal/README.md index 0947470..b32089e 100644 --- a/release-schedule-proposal/README.md +++ b/release-schedule-proposal/README.md @@ -32,21 +32,30 @@ Here are the release schedule proposals: ## Status quo - 1. current duration: 6 months - 2. active duration: - - for even-numbered releases: 12 months - - for odd-numbered releases: 0 months - 3. maintenance duration: - - for even-numbered releases: 18 months - - for odd-numbered releases: 3 months + 1. Current duration: 6 months + 2. Active duration: + - For even-numbered releases: 12 months + - For odd-numbered releases: 0 months + 3. Maintenance duration: + - For even-numbered releases: 18 months + - For odd-numbered releases: 3 months - Total life span (from start of beta until end of maintenance): - - for even-numbered releases: 36 months - - for odd-numbered releases: 9 months +Total life span (from start of beta until end of maintenance): + +- For even-numbered releases: 36 months +- For odd-numbered releases: 9 months + +![Release schedule proposal preview](./status-quo.svg) + +![Release schedule proposal preview](./status-quo2030.svg) - ![Release schedule proposal preview](./status-quo.svg) +### Maintainers Feedback - ![Release schedule proposal preview](./status-quo2030.svg) +* Current release cadence (2 majors/year) is seen as burdensome — too many active branches and backports. +* Reducing to one major per year would **lower the number of active release lines**, easing backporting release management. +* **Security releases** would be simpler to coordinate, with fewer simultaneous branches to patch and less overlap between LTS lines. +* Shorter maintenance windows would **limit the volume of non-security backports**, allowing focus on critical fixes only. +* Concerns remain about ecosystem adaptation, but the **reduction in workload is broadly seen as a clear benefit**. ## LTS every year From 64cad306008df94a7ea623f6769a805587e5b8e5 Mon Sep 17 00:00:00 2001 From: RafaelGSS Date: Thu, 16 Oct 2025 15:44:30 -0300 Subject: [PATCH 13/16] add Proposal numbers --- release-schedule-proposal/README.md | 128 ++++++++++++++-------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/release-schedule-proposal/README.md b/release-schedule-proposal/README.md index b32089e..771fe73 100644 --- a/release-schedule-proposal/README.md +++ b/release-schedule-proposal/README.md @@ -32,13 +32,13 @@ Here are the release schedule proposals: ## Status quo - 1. Current duration: 6 months - 2. Active duration: - - For even-numbered releases: 12 months - - For odd-numbered releases: 0 months - 3. Maintenance duration: - - For even-numbered releases: 18 months - - For odd-numbered releases: 3 months +1. Current duration: 6 months +2. Active duration: + - For even-numbered releases: 12 months + - For odd-numbered releases: 0 months +3. Maintenance duration: + - For even-numbered releases: 18 months + - For odd-numbered releases: 3 months Total life span (from start of beta until end of maintenance): @@ -57,19 +57,19 @@ Total life span (from start of beta until end of maintenance): * Shorter maintenance windows would **limit the volume of non-security backports**, allowing focus on critical fixes only. * Concerns remain about ecosystem adaptation, but the **reduction in workload is broadly seen as a clear benefit**. -## LTS every year +## Proposal 1: LTS every year - 1. Alpha duration: 5 months - 2. Beta duration: 1 months - 3. Current duration: 6 months - 4. Active duration: 12 months - 5. Maintenance duration: 18 months +1. Alpha duration: 5 months +2. Beta duration: 1 months +3. Current duration: 6 months +4. Active duration: 12 months +5. Maintenance duration: 18 months - Total life span (from start of beta until end of maintenance): 37 months +Total life span (from start of beta until end of maintenance): 37 months - ![Release schedule proposal preview](./lts-every-year.svg) +![Release schedule proposal preview](./lts-every-year.svg) - ![Release schedule proposal preview](./lts-every-year2030.svg) +![Release schedule proposal preview](./lts-every-year2030.svg) ### Alpha and Beta definition @@ -128,70 +128,70 @@ regular release (potentially ahead of schedule). The difference on a maintenance perspective is that a security release requires locking the CI until all the queued security releases are ready. -## Longer life cycle +## Proposal 2: Longer life cycle - 1. current duration: - - for even-numbered releases: 6 months - - for odd-numbered releases: 12 months - 2. active duration: - - for even-numbered releases: 18 months - - for odd-numbered releases: 0 months - 3. maintenance duration: - - for even-numbered releases: 24 months - - for odd-numbered releases: 2 months +1. current duration: + - for even-numbered releases: 6 months + - for odd-numbered releases: 12 months +2. active duration: + - for even-numbered releases: 18 months + - for odd-numbered releases: 0 months +3. maintenance duration: + - for even-numbered releases: 24 months + - for odd-numbered releases: 2 months - Total life span (from start of beta until end of maintenance): - - for even-numbered releases: 48 months - - for odd-numbered releases: 14 months +Total life span (from start of beta until end of maintenance): +- for even-numbered releases: 48 months +- for odd-numbered releases: 14 months - ![Release schedule proposal preview](./longer-life-cycle.svg) +![Release schedule proposal preview](./longer-life-cycle.svg) - ![Release schedule proposal preview](./longer-life-cycle2030.svg) +![Release schedule proposal preview](./longer-life-cycle2030.svg) -## Less frequent LTS +## Proposal 3: Less frequent LTS - 1. current duration: 6 months - 2. active duration: - - for modulo-4-numbered releases: 24 months - - for other releases: 0 months - 3. maintenance duration: - - for modulo-4-numbered releases: 18 months - - for other releases: 2 months +1. current duration: 6 months +2. active duration: + - for modulo-4-numbered releases: 24 months + - for other releases: 0 months +3. maintenance duration: + - for modulo-4-numbered releases: 18 months + - for other releases: 2 months - Total life span (from start of beta until end of maintenance): - - for module-4-numbered releases: 48 months - - for releases: 8 months +Total life span (from start of beta until end of maintenance): +- for module-4-numbered releases: 48 months +- for releases: 8 months - ![Release schedule proposal preview](./less-frequent-lts.svg) +![Release schedule proposal preview](./less-frequent-lts.svg) - ![Release schedule proposal preview](./less-frequent-lts2030.svg) +![Release schedule proposal preview](./less-frequent-lts2030.svg) -## No Active LTS anymore +## Proposal 4: No Active LTS anymore - 1. current duration: 12 months - 2. active duration: 0 months - 3. maintenance duration: 24 months +1. current duration: 12 months +2. active duration: 0 months +3. maintenance duration: 24 months - Total life span (from start of beta until end of maintenance): 36 months +Total life span (from start of beta until end of maintenance): 36 months - ![Release schedule proposal preview](./no-active-lts.svg) +![Release schedule proposal preview](./no-active-lts.svg) - ![Release schedule proposal preview](./no-active-lts2030.svg) +![Release schedule proposal preview](./no-active-lts2030.svg) -## Rolling semver-major +## Proposal 5: Rolling semver-major - 1. current duration: 6 weeks - 3. active duration: - - 0 weeks - - or 12 months for the October release - 2. maintenance duration: - - 8 weeks - - or 18 months for the October release +1. current duration: 6 weeks +2. active duration: + - 0 weeks + - or 12 months for the October release +3. maintenance duration: + - 8 weeks + - or 18 months for the October release - Total life span (from start of beta until end of maintenance): - - 14 weeks - - or 31 months for the October release +Total life span (from start of beta until end of maintenance): +- 14 weeks +- or 31 months for the October release - ![Release schedule proposal preview](./rolling.svg) +![Release schedule proposal preview](./rolling.svg) - ![Release schedule proposal preview](./rolling2030.svg) +![Release schedule proposal preview](./rolling2030.svg) From 6b702945c8519741bd0adbbcf3dcb88a5556072f Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Fri, 17 Oct 2025 13:17:07 +0100 Subject: [PATCH 14/16] Update README.md --- release-schedule-proposal/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/release-schedule-proposal/README.md b/release-schedule-proposal/README.md index 771fe73..edb4bac 100644 --- a/release-schedule-proposal/README.md +++ b/release-schedule-proposal/README.md @@ -17,6 +17,8 @@ node ./bin/lts.js >> release-schedule-proposal/README.md ## Dependency lifecycles +(Non-exhaustive list) + | Dependency | LTS policy | Notes | |-|-|-| | c-ares | Unknown | - | From fa2e548b99866b5b6e474d0562776b30d18b03b7 Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Fri, 17 Oct 2025 13:34:00 +0100 Subject: [PATCH 15/16] Update README.md --- release-schedule-proposal/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/release-schedule-proposal/README.md b/release-schedule-proposal/README.md index edb4bac..309ff6e 100644 --- a/release-schedule-proposal/README.md +++ b/release-schedule-proposal/README.md @@ -58,6 +58,7 @@ Total life span (from start of beta until end of maintenance): * **Security releases** would be simpler to coordinate, with fewer simultaneous branches to patch and less overlap between LTS lines. * Shorter maintenance windows would **limit the volume of non-security backports**, allowing focus on critical fixes only. * Concerns remain about ecosystem adaptation, but the **reduction in workload is broadly seen as a clear benefit**. +* Using current to field test changes for regressions not caught by tests before landing on LTS. ## Proposal 1: LTS every year From dff079a65d8a45f9133c039bd76a78bbd65e43e1 Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Fri, 17 Oct 2025 13:34:50 +0100 Subject: [PATCH 16/16] Update README.md --- release-schedule-proposal/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-schedule-proposal/README.md b/release-schedule-proposal/README.md index 309ff6e..811d9b1 100644 --- a/release-schedule-proposal/README.md +++ b/release-schedule-proposal/README.md @@ -58,7 +58,7 @@ Total life span (from start of beta until end of maintenance): * **Security releases** would be simpler to coordinate, with fewer simultaneous branches to patch and less overlap between LTS lines. * Shorter maintenance windows would **limit the volume of non-security backports**, allowing focus on critical fixes only. * Concerns remain about ecosystem adaptation, but the **reduction in workload is broadly seen as a clear benefit**. -* Using current to field test changes for regressions not caught by tests before landing on LTS. +* Using current releases to field test changes for regressions not caught by tests before landing on LTS. ## Proposal 1: LTS every year