[TikiWiki-commits] [Git][tikiwiki/tiki][master] [ENH] Continuous integration (CI): Add a test about alphabetical sorting of...

Benoit Grégoire (@benoitg) via TikiWiki-cvs <[email protected]>
Newsgroups gmane.comp.cms.tiki.cvs
Message-ID <6902806a1cb_2ce1cd054cb@gitlab-sidekiq-low-urgency-cpu-bound-v2-659d96848d-mljcp.mail>

Benoit Grégoire pushed to branch master at Tiki Wiki CMS Groupware / Tiki


Commits:
19e5ae44 by David Maene at 2025-10-29T20:52:36+00:00
[ENH] Continuous integration (CI): Add a test about alphabetical sorting of...
---
* [REF] Simplified the function so that it only focuses on checking the order of dependencies

* [ENH] make this script to handle package.json files

* [ENH] CI - Add check for alphabetical sorting of dependencies

* [REF] Continuous integration (CI): Add a test about alphabetical sorting of lists in Tiki source code

See merge request tikiwiki/tiki!8720

- - - - -


7 changed files:

- .gitlab-ci.yml
- + doc/devtools/check_alphabetical_list.php
- path_constants.php
- src/js/common-externals/package.json
- src/js/jquery-tiki/package.json
- vendor_bundled/composer.json
- vendor_bundled/composer.lock


Changes:

=====================================
.gitlab-ci.yml
=====================================
@@ -737,3 +737,18 @@ composer-operator-check:
     - if: $CI_PIPELINE_SOURCE == "push"
       when: always
   allow_failure: false
+
+check-alphabetical-list:
+  stage: unit-tests
+  image: ${DEPENDENCY_PROXY_PREFIX}${BASE_QA_IMAGE}
+  needs:
+    - composer
+  script:
+    - chmod +x doc/devtools/check_alphabetical_list.php
+    - php doc/devtools/check_alphabetical_list.php
+  rules:
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+      when: always
+    - if: $CI_PIPELINE_SOURCE == "push"
+      when: always
+  allow_failure: false


=====================================
doc/devtools/check_alphabetical_list.php
=====================================
@@ -0,0 +1,160 @@
+<?php
+
+require_once __DIR__ . '/../../path_constants.php';
+
+/**
+ * Returns colored text for console output.
+ */
+
+function colorText(string $text, string $color): string
+{
+    static $colors = [
+        'red'    => "\033[31m",
+        'green'  => "\033[32m",
+        'yellow' => "\033[33m",
+        'blue'   => "\033[34m",
+        'white'  => "\033[1;37m",
+        'reset'  => "\033[0m",
+    ];
+
+    return ($colors[$color] ?? '') . $text . $colors['reset'];
+}
+
+/**
+ * Loads and decodes a JSON file.
+ */
+
+function getJsonData(string $path): array
+{
+    $content = file_get_contents($path);
+    if ($content === false) {
+        throw new RuntimeException("Failed to read $path");
+    }
+
+    $data = json_decode($content, true);
+    if (json_last_error() !== JSON_ERROR_NONE) {
+        throw new RuntimeException("Invalid JSON in $path: " . json_last_error_msg());
+    }
+
+    return $data;
+}
+
+/**
+ * Detects sections that appear to describe dependencies
+ * (based on key name patterns like "require" or "dependency").
+ */
+function detectDependencySections(array $data): array
+{
+    $sections = [];
+
+    foreach ($data as $key => $value) {
+        if (! is_array($value)) {
+            continue;
+        }
+
+        // Detect keys that look like dependency sections
+        if (preg_match('/(require|dependenc(y|ies)|deps)$/i', $key)) {
+            // Must be associative (package => version)
+            if (isAssociativeArray($value) && looksLikeDependencyMap($value)) {
+                $sections[] = $key;
+            }
+        }
+    }
+
+    return $sections;
+}
+
+/**
+ * Checks if array is associative.
+ */
+function isAssociativeArray(array $arr): bool
+{
+    return array_keys($arr) !== range(0, count($arr) - 1);
+}
+
+/**
+ * Heuristic: determine if a section looks like dependencies
+ * (keys are strings, values are strings or numbers)
+ */
+function looksLikeDependencyMap(array $section): bool
+{
+    $sample = array_slice($section, 0, 3, true);
+    foreach ($sample as $k => $v) {
+        if (! is_string($k)) {
+            return false;
+        }
+        if (! is_string($v) && ! is_numeric($v)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+/**
+ * Checks if dependencies in a given section are alphabetically sorted.
+ */
+function checkDependenciesOrder(array $data, string $section, string $file): bool
+{
+    $deps = $data[$section] ?? null;
+    if (! is_array($deps) || empty($deps)) {
+        return true;
+    }
+
+    $keys = array_keys($deps);
+    $sorted = $keys;
+    sort($sorted, SORT_STRING);
+
+    if ($keys !== $sorted) {
+        echo colorText("⚠️  Dependencies in '$section' of '$file' are not sorted alphabetically.\n", 'yellow');
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ * Main validation runner.
+ */
+function main(): void
+{
+    $files = [
+        PRIMARY_COMPOSERJSON_FILE_PATH,
+        PRIMARY_PACKAGEJSON_FILE_PATH,
+        PRIMARY_JQUERYTIKI_PACKAGEJSON_FILE_PATH,
+        PRIMARY_EXTERNAL_PACKAGEJSON_FILE_PATH,
+    ];
+
+    $hasError = false;
+
+    foreach ($files as $file) {
+        $data = getJsonData($file);
+        $sections = detectDependencySections($data);
+
+        if (empty($sections)) {
+            echo colorText("ℹ️  No dependency sections found in $file\n", 'blue');
+            continue;
+        }
+
+        $fileHasError = false;
+        foreach ($sections as $section) {
+            if (! checkDependenciesOrder($data, $section, $file)) {
+                $fileHasError = true;
+                $hasError = true;
+            }
+        }
+
+        if (! $fileHasError) {
+            echo colorText("✅ $file dependencies are properly sorted.\n", 'green');
+        }
+    }
+
+    if ($hasError) {
+        echo colorText("\n❌ CI FAILURE: Some dependencies are unsorted.\n", 'red');
+        exit(1);
+    }
+
+    echo colorText("\nAll dependency sections are sorted correctly.\n", 'green');
+    exit(0);
+}
+
+main();


=====================================
path_constants.php
=====================================
@@ -163,6 +163,10 @@ const PRIMARY_AUTOLOAD_FILE_PATH = 'vendor_bundled/vendor/autoload.php';
 const PRIMARY_COMPOSERJSON_FILE_PATH = 'vendor_bundled/composer.json';
 const COMPOSERLOCK_FILE_PATH = 'vendor_bundled/composer.lock';
 
+const PRIMARY_PACKAGEJSON_FILE_PATH = 'package.json';
+const PRIMARY_PACKAGERLOCK_FILE_PATH = 'package-lock.json';
+const PRIMARY_JQUERYTIKI_PACKAGEJSON_FILE_PATH = 'src/js/jquery-tiki/package.json';
+const PRIMARY_EXTERNAL_PACKAGEJSON_FILE_PATH = 'src/js/common-externals/package.json';
 
 /* BEGIN - HTTP PATHS */
 const HTTP_PUBLIC_PATH = 'public';


=====================================
src/js/common-externals/package.json
=====================================
@@ -31,27 +31,27 @@
     "jquery": "^3.7.1",
     "jquery-form": "^4.3.0",
     "jquery-migrate": "^3.4.1",
-    "jquery-ui": "^1.13.2",
-    "jquery-validation": "1.20.0",
     "jquery-tagcanvas": "2.9.0",
     "jquery-treetable": "^3.2.0-1",
+    "jquery-ui": "^1.13.2",
+    "jquery-validation": "1.20.0",
     "jquery-zoom": "^1.7.21",
     "minicart": "^3.0.6",
     "moment": "^2.30.1",
     "ol": "^10.3.1",
     "ol-layerswitcher": ">=3.3.0",
+    "plotly.js": "^3.0.3",
     "recordrtc": "^5.6.2",
+    "reveal.js": "5.1.0",
     "sass-svg-uri": "^2.0.0",
     "signature_pad": "^5.0.4",
     "smartmenus": "^2.0.0-alpha.1",
-    "timeago": "^1.6.7",
-    "plotly.js": "^3.0.3",
-    "reveal.js": "5.1.0",
     "sortablejs": "=1.14.0",
     "subtotal": "^1.11.0-alpha.0",
     "swagger-ui-dist": "^5.18.2",
-    "tablesorter": "^2.32.0",
     "swiper": "^11.2.6",
+    "tablesorter": "^2.32.0",
+    "timeago": "^1.6.7",
     "vis-timeline": "^7.7.4",
     "vue": "^3.5.12",
     "vue3-sfc-loader": "^0.9.5"


=====================================
src/js/jquery-tiki/package.json
=====================================
@@ -16,9 +16,9 @@
     "@svgedit/svgcanvas": "https://github.com/SVG-Edit/svgedit/blob/master/packages/svgcanvas/CHANGES.md"
   },
   "devDependencies": {
+    "@event-calendar/core": "^4.5.1",
     "@svgedit/svgcanvas": "^7.2.1",
     "async-es": "^3.2.6",
-    "summernote": "^0.9.1",
-    "@event-calendar/core": "^4.5.1"
+    "summernote": "^0.9.1"
   }
 }
\ No newline at end of file


=====================================
vendor_bundled/composer.json
=====================================
@@ -248,9 +248,9 @@
         "phpxmlrpc/phpxmlrpc": "~4.11",
         "pragmarx/google2fa": "~9.0",
         "rambomst/php-bounce-handler": "~1.6",
-        "react/child-process": "~0.6.4",
         "ramsey/uuid": "~4.9",
         "ratchet/pawl": "~0.4.1",
+        "react/child-process": "~0.6.4",
         "robicch/jquery-gantt": "~6.3",
         "rubix/ml": "~2.5",
         "sabre/dav": "~4.7",
@@ -295,12 +295,12 @@
         "kornrunner/dbunit": "~9.1",
         "mikey179/vfsstream": "~1.6",
         "overtrue/phplint": "~9.0",
+        "php-webdriver/webdriver": "~1.15",
         "phpcompatibility/php-compatibility": "~10.x-dev",
         "phpcsstandards/phpcsutils": "~1.0",
         "phpstan/phpstan": "~2.1",
         "phpstan/phpstan-deprecation-rules": "~2.0",
         "phpunit/phpunit": "~10.5.26",
-        "php-webdriver/webdriver": "~1.15",
         "rector/rector": "~2.0",
         "sebastian/diff": "~5.1",
         "squizlabs/php_codesniffer": "~3.1",


=====================================
vendor_bundled/composer.lock
=====================================
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "27e29f0ca322ceace3f65122724a55eb",
+    "content-hash": "38351e87463d7fc688fb1ff3128a12a9",
     "packages": [
         {
             "name": "amphp/amp",



View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/19e5ae44d318a08c59c55234dd49df0270ed6f64

-- 
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/19e5ae44d318a08c59c55234dd49df0270ed6f64
You're receiving this email because of your account on gitlab.com.

_______________________________________________
TikiWiki-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.