From 9e099f97d95525b1b6ce50d32c15a312ce45500f Mon Sep 17 00:00:00 2001 From: Martin Gano Date: Thu, 6 Aug 2020 16:58:47 +0200 Subject: [PATCH] add script with support parsing releases from git --- docs/chart.png | Bin 0 -> 63342 bytes docs/en/versions.rst | 2 + generate_chart.py | 265 +++++++++++++++++++++++++++++++++++++++++++ idf_versions.js | 96 ++++++++++++++++ 4 files changed, 363 insertions(+) create mode 100644 docs/chart.png create mode 100644 generate_chart.py create mode 100644 idf_versions.js diff --git a/docs/chart.png b/docs/chart.png new file mode 100644 index 0000000000000000000000000000000000000000..25475313af7cd1cec59038271c5fa82e67d9f3d4 GIT binary patch literal 63342 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 F{{f=4#b*Ej literal 0 HcmV?d00001 diff --git a/docs/en/versions.rst b/docs/en/versions.rst index b289cc7c7f..6abec3dabf 100644 --- a/docs/en/versions.rst +++ b/docs/en/versions.rst @@ -70,6 +70,8 @@ As a general guideline: - If possible, periodically update the project to a new major or minor ESP-IDF version (for example, once a year.) The update process should be straightforward for Minor updates, but may require some planning and checking of the release notes for Major updates. - Always plan to update to a newer release before the release you are using becomes End of Life. +.. image:: ../chart.png + Checking the Current Version ---------------------------- diff --git a/generate_chart.py b/generate_chart.py new file mode 100644 index 0000000000..d1f61743dc --- /dev/null +++ b/generate_chart.py @@ -0,0 +1,265 @@ +#!/usr/bin/env python +import datetime as dt +import requests +import json +import os +import re + +import matplotlib.dates +import matplotlib.font_manager as font_manager +import matplotlib.patches as mpatches +import matplotlib.pyplot as plt +import numpy as np +from dateutil import parser +from dateutil.relativedelta import relativedelta +from matplotlib.dates import WEEKLY, DateFormatter, RRuleLocator, rrulewrapper + + +class Version(object): + def __init__(self, version_name, + explicit_start_date=None, + explicit_end_date=None, + explicit_end_service_date=None, + is_lts=None): + self.version_name = version_name + + self.is_lts = is_lts or self.is_version_lts() + + self.is_major_minor = Version.is_minor_major_version(self.version_name) + + self._start_date = parser.parse( + explicit_start_date) if explicit_start_date is not None else self._retrieve_start_date() + self._end_of_life_date = parser.parse( + explicit_end_date) if explicit_end_date is not None else self._retrieve_end_of_life_date() + self._end_service_date = parser.parse( + explicit_end_service_date) if explicit_end_service_date is not None else self.get_end_service_date() + + self.start_date_matplotlib_format = matplotlib.dates.date2num(self._start_date) + self.end_of_life_date_matplotlib_format = matplotlib.dates.date2num(self._end_of_life_date) + + self.end_service_date_matplotlib_format = matplotlib.dates.date2num( + self._end_service_date) if self._end_service_date is not None else None + + @staticmethod + def get_config(config_path): + return json.load(open(config_path)) + + @staticmethod + def add_months(source_date, months): + return source_date + relativedelta(months=+months) + + @staticmethod + def is_minor_major_version(version_name): + return True if len(version_name.split(".")) <= 2 else False + + def is_version_lts(self): + version = self.version_name + return version >= 'v4.1' + + def get_start_date(self): + return self._start_date + + def get_end_of_life_date(self): + return self._end_of_life_date + + def _retrieve_start_date(self): + return parser.parse(os.popen("git log -1 --format=%ai " + self.version_name)) + + def _retrieve_end_of_life_date(self): + return self.add_months(self._start_date, 30 if self.is_lts else 18) + + def get_end_service_date(self): + return self.add_months(self._start_date, 12) + + +class ChartVersions(object): + def __init__(self): + self.all_versions = self.get_all_versions_from_git() + + self._releases = self._get_releases_from_url(url="https://dl.espressif.com/dl/esp-idf/idf_versions.js") + self._patches = self._get_patches_from_url(url="https://dl.espressif.com/dl/esp-idf/idf_versions.js") + + self.sorted_releases_supported = sorted(self.filter_old_versions(self._releases), key=lambda x: x.version_name) + self.patches_supported = self.filter_old_versions(self._patches) + + # TODO test higher versions + # self.sorted_releases_supported.append(Version(version_name='v4.1', explicit_start_date="28-9-2020")) + # self.sorted_releases_supported.append(Version(version_name='v4.2', explicit_start_date="28-5-2021")) + + def get_releases_as_json(self): + return { + x.version_name: { + "start_date": x.get_start_date().strftime("%Y-%m-%d"), + "end_date": x.get_end_of_life_date().strftime("%Y-%m-%d"), + "is_lts": x.is_lts + } for x in self.sorted_releases_supported + self.patches_supported + } + + @staticmethod + def parse_chart_releases_from_js(js_as_string): + return json.loads(js_as_string[js_as_string.find("RELEASES: ") + len("RELEASES: "):js_as_string.rfind("};")]) + + def _get_all_version_from_url(self, url=None, filename=None): + releases_file = requests.get(url).text if url is not None else "".join(open(filename).readlines()) + return self.parse_chart_releases_from_js(releases_file) + + def _get_releases_from_url(self, url=None, filename=None): + all_versions = self._get_all_version_from_url(url, filename) + return [ + Version(version_name=x, + explicit_start_date=all_versions[x]['start_date'], + explicit_end_date=all_versions[x]['end_date'] if 'end_date' in all_versions[x].keys() else None, + explicit_end_service_date=all_versions[x]['end_service'] if 'end_service' in all_versions[x].keys() else None) + for x in all_versions.keys() if Version.is_minor_major_version(x) + ] + + def _get_patches_from_url(self, url=None, filename=None): + all_versions = self._get_all_version_from_url(url, filename) + return [ + Version(version_name=x, + explicit_start_date=all_versions[x]['start_date'], + explicit_end_date=all_versions[x]['end_date'] if 'end_date' in all_versions[x].keys() else None, + is_lts=all_versions[x]['new_policy'] if 'new_policy' in all_versions[x].keys() else None) + for x in all_versions.keys() if not Version.is_minor_major_version(x) + ] + + def _get_releases(self, all_versions): + return [Version(release) for release in self._get_releases_names(all_versions)] + + def _get_patches(self, all_versions): + return [Version(patch, explicit_end_date=self.get_super_end_date_as_string(patch), + is_lts=self.get_super_lts_state(patch)) for patch in self._get_patches_names(all_versions)] + + @staticmethod + def _get_releases_names(all_versions): + return list(filter(lambda x: Version.is_minor_major_version(x), all_versions)) + + @staticmethod + def _get_patches_names(all_versions): + return list(filter(lambda x: not Version.is_minor_major_version(x), all_versions)) + + def get_super_version(self, patch): + return list(filter(lambda x: x.version_name == self.get_super_version_name(patch), self._releases))[0] + + def get_super_end_date_as_string(self, patch): + return self.get_super_version(patch).get_end_of_life_date().strftime("%m/%d/%Y, %H:%M:%S") + + def get_super_lts_state(self, patch): + return self.get_super_version(patch).is_lts + + @staticmethod + def get_all_versions_from_git(): + """ + :returns: list of string variables meaning name of the versions or patches (e.g. v4.1, v3.3.1, etc.) + """ + all_git_tags = os.popen("git tag") + stable_releases_regex = "(?:^|)(v\d+\.\d+(?:\.\d+){0,1})(?=\n|$)" + + results = [re.match(stable_releases_regex, line) for line in all_git_tags] + all_versions = [regex_result.group(1) for regex_result in results if regex_result is not None] + return all_versions + + @staticmethod + def filter_old_versions(versions): + return list( + filter(lambda x: x.get_end_of_life_date() >= dt.datetime.now(x.get_end_of_life_date().tzinfo), versions)) + + @staticmethod + def get_super_version_name(version_name): + return ".".join(version_name.split(".")[:2]) + + def create_chart(self, + figure_size=(20, 8), + subplot=111, + step_size=0.5, + bar_height=0.3, + version_alpha=0.8, + patch_width=1, + lts_service_color='darkred', + lts_maintenance_color='red', + bar_align='center', + patch_color='black', + patch_alpha=1, + date_interval=10, + output_chart_name='docs/chart', + output_chart_extension='.png', + months_surrounding_chart=5): + fig = plt.figure(figsize=figure_size) + ax = fig.add_subplot(subplot) + + labels_count = len(self.sorted_releases_supported) + + pos = np.arange(step_size, labels_count * step_size + step_size, step_size) + mapping_releases_index = {release.version_name: i for release, i in + zip(self.sorted_releases_supported, range(labels_count))} + + for release, i in zip(self.sorted_releases_supported, range(labels_count)): + start_date = release.start_date_matplotlib_format + end_of_service_date = release.end_service_date_matplotlib_format + + end_date = release.end_of_life_date_matplotlib_format + + ax.barh((i * step_size) + step_size, (end_of_service_date or end_date) - start_date, left=start_date, + height=bar_height, align=bar_align, + color=lts_service_color, + alpha=version_alpha, + edgecolor=lts_service_color) + if end_of_service_date is not None: + ax.barh((i * step_size) + step_size, end_date - end_of_service_date, left=end_of_service_date, + height=bar_height, align=bar_align, + color=lts_maintenance_color, alpha=version_alpha, edgecolor=lts_maintenance_color) + + for patch, i in zip(self.patches_supported, range(len(self.patches_supported))): + start_date = patch.start_date_matplotlib_format + + ax.barh(mapping_releases_index[self.get_super_version_name(patch.version_name)] * step_size + step_size, + patch_width, left=start_date, height=bar_height, align=bar_align, color=patch_color, + alpha=patch_alpha, + edgecolor=patch_color) + ax.text(start_date - 5, mapping_releases_index[ + self.get_super_version_name(patch.version_name)] * step_size + step_size - 0.2, + patch.version_name.split('.')[-1], + fontsize='xx-small', color='darkred') + + plt.setp(plt.yticks(pos, map(lambda x: x.version_name, self.sorted_releases_supported))[1], fontsize=14) + + ax.set_ylim(bottom=0, ymax=labels_count * step_size + step_size) + + ax.set_xlim( + xmin=Version.add_months( + min(self.sorted_releases_supported, + key=lambda version: version.get_start_date().replace(tzinfo=None)).get_start_date(), + -months_surrounding_chart), + xmax=Version.add_months( + max(self.sorted_releases_supported, + key=lambda version: version.get_end_of_life_date().replace(tzinfo=None)).get_end_of_life_date(), + months_surrounding_chart)) + + ax.grid(color='g', linestyle=':') + ax.xaxis_date() + + rule = rrulewrapper(WEEKLY, interval=date_interval) + loc = RRuleLocator(rule) + formatter = DateFormatter("%d-%b '%y") + + ax.xaxis.set_major_locator(loc) + ax.xaxis.set_major_formatter(formatter) + x_labels = ax.get_xticklabels() + plt.setp(x_labels, rotation=30, fontsize=10) + + ax.legend(loc=1, prop=font_manager.FontProperties(size='small')) + + ax.invert_yaxis() + fig.autofmt_xdate() + + darkred_patch = mpatches.Patch(color='darkred', label='Service period (Recommended for new designs)') + red_patch = mpatches.Patch(color='red', label='Maintenance period') + + plt.legend(handles=[darkred_patch, red_patch], prop={'size': 6}) + fig.set_size_inches(10, 5, forward=True) + plt.savefig(output_chart_name + output_chart_extension) + plt.show() + + +if __name__ == '__main__': + ChartVersions().create_chart() diff --git a/idf_versions.js b/idf_versions.js new file mode 100644 index 0000000000..d36ec3182c --- /dev/null +++ b/idf_versions.js @@ -0,0 +1,96 @@ +var DOCUMENTATION_VERSIONS = { + DEFAULTS: { + has_targets: false, + supported_targets: ["esp32"] + }, + VERSIONS: [{ + name: "latest", + has_targets: true, + supported_targets: ["esp32", "esp32s2"] + }, + { + name: "v4.1-rc", + pre_release: true + }, + { + name: "v4.0.1", + old: false + }, + { + name: "v4.0", + old: true + }, + { + name: "v3.3.2" + }, + { + name: "v3.3.1", + old: true + }, + { + name: "v3.3", + old: true + }, + { + name: "v3.2.3", + old: false + }, + { + name: "v3.1.7", + old: false + }, + { + name: "v3.1.6", + old: true + }, + { + name: "v3.0.9", + old: true + }, + { + name: "release-v4.2", + pre_release: true, + has_targets: true, + supported_targets: ["esp32", "esp32s2"] + }, + { + name: "release-v4.1", + pre_release: true + }, + { + name: "release-v4.0", + pre_release: true + }, + { + name: "release-v3.3", + pre_release: true + }, + { + name: "release-v3.2", + pre_release: true + }, + { + name: "release-v3.1", + pre_release: true + } + ], + RELEASES: { + "v3.1": { + "start_date": "2018-09-07", + "end_date": "2020-10-31" + }, + "v3.2": { + "start_date": "2019-04-11", + "end_date": "2020-10-31" + }, + "v3.3": { + "start_date": "2019-09-05", + "end_date": "2022-03-31" + }, + "v4.0": { + "start_date": "2020-02-11", + "end_service": "2021-02-11", + "end_date": "2021-10-31" + } + } +};