Update dependencies and workflows #444
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Tests | |
| on: [push, pull_request] | |
| jobs: | |
| resolve-node-versions: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.set-matrix.outputs.matrix }} | |
| steps: | |
| - id: set-matrix | |
| run: | | |
| node <<'EOF' >> $GITHUB_OUTPUT | |
| const https = require('https'); | |
| const fs = require('fs'); | |
| function compareSemver(a, b) { | |
| const pa = a.split('.').map(Number); | |
| const pb = b.split('.').map(Number); | |
| for (let i = 0; i < 3; i++) { | |
| if ((pa[i] ?? 0) !== (pb[i] ?? 0)) return (pb[i] ?? 0) - (pa[i] ?? 0); | |
| } | |
| return 0; | |
| } | |
| function parseEnginesVersion(enginesNode) { | |
| if (!enginesNode) return null; | |
| const match = enginesNode.match(/>=\s*(\d+)(?:\.(\d+)(?:\.(\d+))?)?/); | |
| if (!match) return null; | |
| return { | |
| major: parseInt(match[1], 10), | |
| minor: match[2] !== undefined ? parseInt(match[2], 10) : null, | |
| patch: match[3] !== undefined ? parseInt(match[3], 10) : null, | |
| }; | |
| } | |
| let enginesNode = null; | |
| try { | |
| const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8')); | |
| enginesNode = pkg?.engines?.node ?? null; | |
| } catch {} | |
| const minVersion = parseEnginesVersion(enginesNode); | |
| https.get('https://nodejs.org/dist/index.json', res => { | |
| let data = ''; | |
| res.on('data', chunk => data += chunk); | |
| res.on('end', () => { | |
| const releases = JSON.parse(data); | |
| // All LTS versions, stripped of 'v' prefix | |
| const lts = releases | |
| .filter(r => r.lts) | |
| .map(r => r.version.replace(/^v/, '')); | |
| // Group by major, pick highest semver per major, sort descending, take top 4 | |
| const byMajor = {}; | |
| for (const v of lts) { | |
| const major = parseInt(v.split('.')[0], 10); | |
| if (!byMajor[major]) byMajor[major] = []; | |
| byMajor[major].push(v); | |
| } | |
| const top4 = Object.entries(byMajor) | |
| .map(([major, versions]) => { | |
| versions.sort(compareSemver); | |
| return versions[0]; // latest patch for this major | |
| }) | |
| .sort(compareSemver) | |
| .slice(0, 4); | |
| // Find the latest LTS version satisfying the engines constraint: | |
| // - major must match | |
| // - if minor specified, minor must match | |
| // - if patch specified, patch must match | |
| let minMatch = null; | |
| if (minVersion !== null) { | |
| const candidates = lts.filter(v => { | |
| const [maj, min, pat] = v.split('.').map(Number); | |
| if (maj !== minVersion.major) return false; | |
| if (minVersion.minor !== null && min !== minVersion.minor) return false; | |
| if (minVersion.patch !== null && pat !== minVersion.patch) return false; | |
| return true; | |
| }); | |
| candidates.sort(compareSemver); | |
| minMatch = candidates[0] ?? null; // highest version matching the constraint | |
| } | |
| // Add minMatch only if it isn't already in top4 | |
| const versions = [...top4]; | |
| if (minMatch !== null && !versions.includes(minMatch)) { | |
| versions.push(minMatch); | |
| } | |
| // Sort ascending (oldest to newest) for natural CI output | |
| versions.sort((a, b) => compareSemver(b, a)); | |
| const matrix = { 'node': versions }; | |
| console.log(`matrix=${JSON.stringify(matrix)}`); | |
| }); | |
| }); | |
| EOF | |
| test: | |
| needs: resolve-node-versions | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: ${{ fromJson(needs.resolve-node-versions.outputs.matrix) }} | |
| name: Node ${{ matrix.node }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Use Node.js ${{ matrix.node }} | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ matrix.node }} | |
| - name: Enable Corepack | |
| run: corepack enable | |
| - name: Detect Yarn version | |
| id: yarn-version | |
| run: | | |
| YARN_VERSION=$(node -p " | |
| try { | |
| const pm = require('./package.json').packageManager ?? ''; | |
| const match = pm.match(/^yarn@(\d+)/); | |
| match ? match[1] : ''; | |
| } catch { '' } | |
| ") | |
| if [ -z "$YARN_VERSION" ]; then | |
| YARN_VERSION=$(yarn --version | cut -d. -f1) | |
| fi | |
| echo "major=$YARN_VERSION" >> "$GITHUB_OUTPUT" | |
| echo "Detected Yarn major version: $YARN_VERSION" | |
| - name: Install dependencies | |
| run: | | |
| if [ "${{ steps.yarn-version.outputs.major }}" = "1" ]; then | |
| yarn install --frozen-lockfile --non-interactive --prefer-offline | |
| else | |
| yarn install --immutable | |
| fi | |
| - name: Lint | |
| run: yarn lint | |
| - name: Test | |
| run: yarn test |