From be26e3df7fea7781c19e7b700dbdc73e240de222 Mon Sep 17 00:00:00 2001 From: tleb Date: Tue, 5 May 2020 17:32:17 +0200 Subject: [PATCH] core: add ./manage.py check_front command and call it on runserver --- core/management/commands/check_front.py | 107 ++++++++++++++++++++++++ doc/start/install.rst | 11 +++ sith/settings.py | 17 +++- 3 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 core/management/commands/check_front.py diff --git a/core/management/commands/check_front.py b/core/management/commands/check_front.py new file mode 100644 index 00000000..181de23c --- /dev/null +++ b/core/management/commands/check_front.py @@ -0,0 +1,107 @@ +import re +from subprocess import PIPE, Popen, TimeoutExpired + +from django.conf import settings +from django.core.management.base import BaseCommand + +# see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string +# added "v?" +semver_regex = re.compile( + """^v?(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)(?:-(?P(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$""" +) + + +class Command(BaseCommand): + help = "Checks the front dependencies are up to date." + + def handle(self, *args, **options): + deps = settings.SITH_FRONT_DEP_VERSIONS + + processes = dict( + (url, create_process(url)) + for url in deps.keys() + if parse_semver(deps[url]) is not None + ) + + for url, process in processes.items(): + try: + stdout, stderr = process.communicate(timeout=15) + except TimeoutExpired: + process.kill() + self.stderr.write(self.style.WARNING("{}: timeout".format(url))) + continue + # error, notice, warning + + stdout = stdout.decode("utf-8") + stderr = stderr.decode("utf-8") + + if stderr != "": + self.stderr.write(self.style.WARNING(stderr.strip())) + continue + + # get all tags, parse them as semvers and find the biggest + tags = list_tags(stdout) + tags = map(parse_semver, tags) + tags = filter(lambda tag: tag is not None, tags) + latest_version = max(tags) + + # cannot fail as those which fail are filtered in the processes dict creation + current_version = parse_semver(deps[url]) + assert current_version is not None + + if latest_version == current_version: + msg = "{}: {}".format(url, semver_to_s(current_version)) + self.stdout.write(self.style.SUCCESS(msg)) + else: + msg = "{}: {} < {}".format( + url, semver_to_s(current_version), semver_to_s(latest_version) + ) + self.stdout.write(self.style.ERROR(msg)) + + +def create_process(url): + """Spawn a "git ls-remote --tags" child process.""" + return Popen(["git", "ls-remote", "--tags", url], stdout=PIPE, stderr=PIPE) + + +def list_tags(s): + """Parses "git ls-remote --tags" output. Takes a string.""" + tag_prefix = "refs/tags/" + + for line in s.strip().split("\n"): + # an example line could be: + # "1f41e2293f9c3c1962d2d97afa666207b98a222a\trefs/tags/foo" + parts = line.split("\t") + + # check we have a commit ID (SHA-1 hash) and a tag name + assert len(parts) == 2 + assert len(parts[0]) == 40 + assert parts[1].startswith(tag_prefix) + + # avoid duplicates (a peeled tag will appear twice: as "name" and as "name^{}") + if not parts[1].endswith("^{}"): + yield parts[1][len(tag_prefix) :] + + +def parse_semver(s): + """ + Turns a semver string into a 3-tuple or None if the parsing failed, it is a + prerelease or it has build metadata. + + See https://semver.org + """ + m = semver_regex.match(s) + + if ( + m is None + or m.group("prerelease") is not None + or m.group("buildmetadata") is not None + ): + return None + + return (int(m.group("major")), int(m.group("minor")), int(m.group("patch"))) + + +def semver_to_s(t): + """Expects a 3-tuple with ints and turns it into a string of type "1.2.3".""" + return "{}.{}.{}".format(t[0], t[1], t[2]) diff --git a/doc/start/install.rst b/doc/start/install.rst index 5a8c9226..502835f0 100644 --- a/doc/start/install.rst +++ b/doc/start/install.rst @@ -133,3 +133,14 @@ Pour lancer les tests il suffit d'utiliser la commande intégrée à django. # Lancer une méthode en particulier de cette même classe ./manage.py test core.tests.UserRegistrationTest.test_register_user_form_ok + +Vérifier les dépendances Javascript +----------------------------------- + +Une commande a été écrite pour vérifier les éventuelles mises à jour à faire sur les librairies Javascript utilisées. +N'oubliez pas de mettre à jour à la fois le fichier de la librairie, mais également sa version dans `sith/settings.py`. + +.. code-block:: bash + + # Vérifier les mises à jour + ./manage.py check_front diff --git a/sith/settings.py b/sith/settings.py index 3849c4bd..fcfadebd 100644 --- a/sith/settings.py +++ b/sith/settings.py @@ -280,7 +280,8 @@ SITH_NAME = "Sith website" SITH_TWITTER = "@ae_utbm" # AE configuration -SITH_MAIN_CLUB_ID = 1 # TODO: keep only that first setting, with the ID, and do the same for the other clubs +# TODO: keep only that first setting, with the ID, and do the same for the other clubs +SITH_MAIN_CLUB_ID = 1 SITH_MAIN_CLUB = { "name": "AE", "unix_name": "ae", @@ -667,3 +668,17 @@ if "test" in sys.argv: if SENTRY_DSN: # Connection to sentry sentry_sdk.init(dsn=SENTRY_DSN, integrations=[DjangoIntegration()]) + + +SITH_FRONT_DEP_VERSIONS = { + "https://github.com/chartjs/Chart.js/": "2.6.0", + "https://github.com/xdan/datetimepicker/": "2.5.21", + "https://github.com/Ionaru/easy-markdown-editor/": "2.7.0", + "https://github.com/FortAwesome/Font-Awesome/": "4.7.0", + "https://github.com/jquery/jquery/": "3.1.0", + "https://github.com/sethmcl/jquery-ui/": "1.11.1", + "https://github.com/viralpatel/jquery.shorten/": "", + "https://github.com/getsentry/sentry-javascript/": "4.0.6", + "https://github.com/jhuckaby/webcamjs/": "1.0.0", + "https://github.com/vuejs/vue-next": "3.2.18", +}