Skip to content
Closed
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ jspm_packages
*.html
*.png
*.svg
!release-schedule-proposal/*.svg
13 changes: 10 additions & 3 deletions bin/lts.js
Original file line number Diff line number Diff line change
Expand Up @@ -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': {
Expand Down Expand Up @@ -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', 'rolling.svg'),
png: args.png ? Path.resolve(args.png) : null,
animate: args.animate,
excludeMain: args.excludeMain,
Expand All @@ -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'),
});
112 changes: 88 additions & 24 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -13,7 +17,7 @@ const styles = `
.maintenance {
fill: #b1bcc2;
}
.unstable {
.unstable,.alpha {
fill: #e99c40;
}
.bar-join {
Expand All @@ -29,20 +33,80 @@ 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 = {
title: 'Rolling semver-major',
currentDuration: { weeks: 6 },
maintenanceDuration: { weeks: 8 },
activeDuration: false,
};

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).weeks : 0} weeks`;
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).weeks, 0)
const ___ = () => hasArray ?
`\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)}`)
}

const __ = (duration_s, i) => Array.isArray(duration_s) ? duration_s[i % duration_s.length] : duration_s;

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 = __(isLTS ? { months: 12} : schedule.activeDuration, i);
const maintenanceDuration = __(isLTS ? {months: 18} : 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;
Expand Down Expand Up @@ -76,7 +140,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({
Expand All @@ -92,7 +169,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 };
Expand All @@ -108,7 +185,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)
Expand Down Expand Up @@ -148,21 +225,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);
Expand Down Expand Up @@ -196,7 +258,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;
}
Expand All @@ -205,7 +267,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;
})
Expand All @@ -226,6 +288,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') {
Expand Down
60 changes: 14 additions & 46 deletions lts.json
Original file line number Diff line number Diff line change
@@ -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": ""
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading