You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by vl...@apache.org on 2026/03/25 14:32:26 UTC

(jmeter) branch master updated: Replace vendored matrix_builder with npm @vlsi/github-actions-random-matrix

This is an automated email from the ASF dual-hosted git repository.

vladimirsitnikov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jmeter.git


The following commit(s) were added to refs/heads/master by this push:
     new e25de766e7 Replace vendored matrix_builder with npm @vlsi/github-actions-random-matrix
e25de766e7 is described below

commit e25de766e7ef72dfbfd84b0ac7641310683bd0b5
Author: Vladimir Sitnikov <si...@gmail.com>
AuthorDate: Wed Mar 25 16:42:37 2026 +0300

    Replace vendored matrix_builder with npm @vlsi/github-actions-random-matrix
    
    Use the published npm package instead of vendored matrix_builder.js,
    converting to ESM modules (.mjs) with seeded RNG from the package.
    
    Co-Authored-By: Claude Opus 4.6 (1M context) <no...@anthropic.com>
---
 .github/workflows/main.yml                  |   3 +-
 .github/workflows/{matrix.js => matrix.mjs} |  14 +-
 .github/workflows/matrix_builder.js         | 255 ----------------------------
 .github/workflows/package-lock.json         |  21 +++
 .github/workflows/package.json              |   7 +
 .gitignore                                  |   1 +
 6 files changed, 38 insertions(+), 263 deletions(-)

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 14164ac079..4a44114626 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -30,7 +30,8 @@ jobs:
       - uses: actions/checkout@v6
       - id: set-matrix
         run: |
-          node .github/workflows/matrix.js
+          npm ci --prefix .github/workflows
+          node .github/workflows/matrix.mjs
 
   test:
     needs: matrix_prep
diff --git a/.github/workflows/matrix.js b/.github/workflows/matrix.mjs
similarity index 93%
rename from .github/workflows/matrix.js
rename to .github/workflows/matrix.mjs
index aad48000fd..fa4f79ca9d 100644
--- a/.github/workflows/matrix.js
+++ b/.github/workflows/matrix.mjs
@@ -1,10 +1,10 @@
 // The script generates a random subset of valid jdk, os, timezone, and other axes.
-// You can preview the results by running "node matrix.js"
+// You can preview the results by running "node matrix.mjs"
 // See https://github.com/vlsi/github-actions-random-matrix
-let fs = require('fs');
-let os = require('os');
-let {MatrixBuilder} = require('./matrix_builder');
-const matrix = new MatrixBuilder();
+import { appendFileSync } from 'fs';
+import { EOL } from 'os';
+import { createGitHubMatrixBuilder } from '@vlsi/github-actions-random-matrix/github';
+const { matrix, random } = createGitHubMatrixBuilder();
 matrix.addAxis({
   name: 'java_distribution',
   values: [
@@ -130,7 +130,7 @@ include.forEach(v => {
       v.oracle_java_website = v.java_version === eaJava ? 'jdk.java.net' : 'oracle.com';
   }
   v.non_ea_java_version = v.java_version === eaJava ? '' : v.java_version;
-  if (v.java_distribution !== 'semeru' && Math.random() > 0.5) {
+  if (v.java_distribution !== 'semeru' && random() > 0.5) {
     // The following options randomize instruction selection in JIT compiler
     // so it might reveal missing synchronization
     v.name += ', stress JIT';
@@ -164,7 +164,7 @@ console.log(include);
 
 let filePath = process.env['GITHUB_OUTPUT'] || '';
 if (filePath) {
-    fs.appendFileSync(filePath, `matrix<<MATRIX_BODY${os.EOL}${JSON.stringify({include})}${os.EOL}MATRIX_BODY${os.EOL}`, {
+    appendFileSync(filePath, `matrix<<MATRIX_BODY${EOL}${JSON.stringify({include})}${EOL}MATRIX_BODY${EOL}`, {
         encoding: 'utf8'
     });
 }
diff --git a/.github/workflows/matrix_builder.js b/.github/workflows/matrix_builder.js
deleted file mode 100644
index 0c17190ede..0000000000
--- a/.github/workflows/matrix_builder.js
+++ /dev/null
@@ -1,255 +0,0 @@
-// License: Apache-2.0
-// Copyright Vladimir Sitnikov, 2021
-// See https://github.com/vlsi/github-actions-random-matrix
-
-class Axis {
-  constructor({name, title, values}) {
-    this.name = name;
-    this.title = title;
-    this.values = values;
-    // If all entries have same weight, the axis has uniform distribution
-    this.uniform = values.reduce((a, b) => a === (b.weight || 1) ? a : 0, values[0].weight || 1) !== 0
-    this.totalWeight = this.uniform ? values.length : values.reduce((a, b) => a + (b.weight || 1), 0);
-  }
-
-  static matches(row, filter) {
-    if (typeof filter === 'function') {
-      return filter(row);
-    }
-    if (Array.isArray(filter)) {
-      // e.g. row={os: 'windows'}; filter=[{os: 'linux'}, {os: 'linux'}]
-      return filter.some(v => Axis.matches(row, v));
-    }
-    if (typeof filter === 'object') {
-      // e.g. row={jdk: {name: 'openjdk', version: 8}}; filter={jdk: {version: 8}}
-      for (const [key, value] of Object.entries(filter)) {
-        if (!row.hasOwnProperty(key) || !Axis.matches(row[key], value)) {
-          return false;
-        }
-      }
-      return true;
-    }
-    return row === filter;
-  }
-
-  pickValue(filter) {
-    let values = this.values;
-    if (filter) {
-      values = values.filter(v => Axis.matches(v, filter));
-    }
-    if (values.length === 0) {
-      const filterStr = typeof filter === 'string' ? filter.toString() : JSON.stringify(filter);
-      throw Error(`No values produces for axis '${this.name}' from ${JSON.stringify(this.values)}, filter=${filterStr}`);
-    }
-    if (values.length === 1) {
-      return values[0];
-    }
-    if (this.uniform) {
-      return values[Math.floor(Math.random() * values.length)];
-    }
-    const totalWeight = !filter ? this.totalWeight : values.reduce((a, b) => a + (b.weight || 1), 0);
-    let weight = Math.random() * totalWeight;
-    for (let i = 0; i < values.length; i++) {
-      const value = values[i];
-      weight -= value.weight || 1;
-      if (weight <= 0) {
-        return value;
-      }
-    }
-    return values[values.length - 1];
-  }
-}
-
-class MatrixBuilder {
-  constructor() {
-    this.axes = [];
-    this.axisByName = {};
-    this.rows = [];
-    this.duplicates = {};
-    this.excludes = [];
-    this.includes = [];
-    this.implications = [];
-    this.failOnUnsatisfiableFilters = false;
-  }
-
-  /**
-   * Specifies include filter (all the generated rows would comply with all the include filters)
-   * @param filter
-   */
-  include(filter) {
-    this.includes.push(filter);
-  }
-
-  /**
-   * Specifies exclude filter (e.g. exclude a forbidden combination).
-   * @param filter
-   */
-  exclude(filter) {
-    this.excludes.push(filter);
-  }
-
-  /**
-   * Adds implication like `antecedent -> consequent`.
-   * In other words, if `antecedent` holds, then `consequent` must also hold.
-   * @param antecedent
-   * @param consequent
-   */
-  imply(antecedent, consequent) {
-    this.implications.push({antecedent: antecedent, consequent: consequent});
-  }
-
-  addAxis({name, title, values}) {
-    const axis = new Axis({name, title, values});
-    this.axes.push(axis);
-    this.axisByName[name] = axis;
-    return axis;
-  }
-
-  setNamePattern(names) {
-    this.namePattern = names;
-  }
-
-  /**
-   * Returns true if the row matches the include and exclude filters.
-   * @param row input row
-   * @returns {boolean}
-   */
-  matches(row) {
-    return (this.excludes.length === 0 || !this.excludes.some(f => Axis.matches(row, f))) &&
-           (this.includes.length === 0 || this.includes.some(f => Axis.matches(row, f))) &&
-           (this.implications.length === 0 || (
-               this.implications.every(i => !Axis.matches(row, i.antecedent) || Axis.matches(row, i.consequent))));
-  }
-
-  failOnUnsatisfiableFilters(value) {
-    this.failOnUnsatisfiableFilters = value;
-  }
-
-  /**
-   * Adds a row that matches the given filter to the resulting matrix.
-   * filter values could be
-   *  - literal values: filter={os: 'windows-latest'}
-   *  - arrays: filter={os: ['windows-latest', 'linux-latest']}
-   *  - functions: filter={os: x => x!='windows-latest'}
-   * @param filter object with keys matching axes names
-   * @returns {*}
-   */
-  generateRow(filter) {
-    let res;
-    if (filter) {
-      // If matching row already exists, no need to generate more
-      res = this.rows.some(v => Axis.matches(v, filter));
-      if (res) {
-        return res;
-      }
-    }
-    for (let i = 0; i < 142; i++) {
-      res = this.axes.reduce(
-        (prev, next) =>
-          Object.assign(prev, {
-            [next.name]: next.pickValue(filter ? filter[next.name] : undefined)
-          }),
-        {}
-      );
-      if (!this.matches(res)) {
-        continue;
-      }
-      const key = JSON.stringify(res);
-      if (!this.duplicates.hasOwnProperty(key)) {
-        this.duplicates[key] = true;
-        res.name =
-          this.namePattern.map(axisName => {
-            let value = res[axisName];
-            const title = value.title;
-            if (typeof title != 'undefined') {
-              return title;
-            }
-            const computeTitle = this.axisByName[axisName].title;
-            if (computeTitle) {
-                return computeTitle(value);
-            }
-            if (typeof value === 'object' && value.hasOwnProperty('value')) {
-                return value.value;
-            }
-            return value;
-          }).filter(Boolean).join(", ");
-        this.rows.push(res);
-        return res;
-      }
-    }
-    const filterStr = typeof filter === 'string' ? filter.toString() : JSON.stringify(filter);
-    const msg = `Unable to generate row for ${filterStr}. Please check include and exclude filters`;
-    if (this.failOnUnsatisfiableFilters) {
-      throw Error(msg);
-    } else {
-      console.warn(msg);
-    }
-  }
-
-  generateRows(maxRows, filter) {
-    for (let i = 0; this.rows.length < maxRows && i < maxRows; i++) {
-      this.generateRow(filter);
-    }
-    return this.rows;
-  }
-
-  /**
-   * Computes the number of all the possible combinations.
-   * @returns {{bad: number, good: number}}
-   */
-  summary() {
-   let position = -1;
-   let indices = [];
-   let values = {};
-   const axes = this.axes;
-   function resetValuesUpTo(nextPosition) {
-     for(let i=0; i<nextPosition; i++) {
-       const axis = axes[i];
-       values[axis.name] = axis.values[0];
-       indices[i] = 1; // next index
-     }
-     position = 0;
-   }
-
-   function nextAvailablePosition() {
-    let size = axes.length;
-    for (let i = position; i < size; i++) {
-      if (indices[i] < axes[i].values.length) {
-        return i;
-      }
-    }
-    return -1;
-   }
-   // The first initialization of the values
-   resetValuesUpTo(this.axes.length);
-   let good = 0;
-   let bad = 0;
-   while (true) {
-     if (indices[position] < this.axes[position].values.length) {
-       // Advance iterator at the current position if possible
-       const axis = this.axes[position];
-       values[axis.name] = axis.values[indices[position]];
-       indices[position]++;
-     } else {
-       // Advance the next iterator, and reset [0..nextPosition)
-       position++;
-       let nextPosition = nextAvailablePosition();
-       if (nextPosition === -1) {
-         break;
-       }
-       const axis = this.axes[nextPosition];
-       values[axis.name] = axis.values[indices[nextPosition]];
-       indices[nextPosition]++;
-       resetValuesUpTo(nextPosition);
-     }
-     if (this.matches(values)) {
-       good++;
-     } else {
-       bad++;
-     }
-   }
-   return {good: good, bad: bad};
-  }
-}
-
-module.exports = {Axis, MatrixBuilder};
diff --git a/.github/workflows/package-lock.json b/.github/workflows/package-lock.json
new file mode 100644
index 0000000000..8e51ba5949
--- /dev/null
+++ b/.github/workflows/package-lock.json
@@ -0,0 +1,21 @@
+{
+  "name": "workflows",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "dependencies": {
+        "@vlsi/github-actions-random-matrix": "2.0.0"
+      }
+    },
+    "node_modules/@vlsi/github-actions-random-matrix": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@vlsi/github-actions-random-matrix/-/github-actions-random-matrix-2.0.0.tgz",
+      "integrity": "sha512-8lEb4eadMBKs+Hnj9dCmcHtgHoWelT4RMXAQ/VcQ1r3vjR8P2hSMVGhkRXaXibCBf0lMttS934CGo2mlBMopPA==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=16"
+      }
+    }
+  }
+}
diff --git a/.github/workflows/package.json b/.github/workflows/package.json
new file mode 100644
index 0000000000..a66b1aa6f4
--- /dev/null
+++ b/.github/workflows/package.json
@@ -0,0 +1,7 @@
+{
+  "private": true,
+  "type": "module",
+  "dependencies": {
+    "@vlsi/github-actions-random-matrix": "2.0.0"
+  }
+}
diff --git a/.gitignore b/.gitignore
index b4714dd560..31dc34b4b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -84,6 +84,7 @@ jmeter-fb.*
 *.iml
 
 # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+node_modules
 hs_err_pid*
 # other jvm related files
 .attach_*