mirror of
				https://github.com/ae-utbm/sith.git
				synced 2025-11-04 02:53:06 +00:00 
			
		
		
		
	Merge branch 'dep-hell2' into 'master'
core: add ./manage.py check_front command and call it on runserver See #92 and !268. This simplifies checking that front-end dependencies are up to date. It does not allow one to update an outdated dependency. That must be done manually (would otherwise require depending on a CDN or add npm as a dependency). A manual update will make sure changelogs are read and changes will be made appropriately. We add a `check_front` command to `manage.py` and run it on calls to `runserver`. This MR does not update any dependency as it is not its goal. MR incoming! Should doc be added? It seems pretty simple and I don't see what should be documented: if it's red, update it. ~"Review TODO" @sli See merge request ae/Sith!271
This commit is contained in:
		
							
								
								
									
										107
									
								
								core/management/commands/check_front.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								core/management/commands/check_front.py
									
									
									
									
									
										Normal file
									
								
							@@ -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?(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>(?: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<buildmetadata>[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])
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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",
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user