From a631d288138b7b6e5d381e216459d57259183392 Mon Sep 17 00:00:00 2001 From: Monica Date: Tue, 20 Aug 2024 13:52:47 +1000 Subject: [PATCH 1/3] Fix releases (#16) --- .github/workflows/release.yml | 27 ++-- .prettierignore | 2 +- README.md | 2 +- packages/core/{atlaspack => cli}/.npmignore | 0 packages/core/{atlaspack => cli}/README.md | 2 +- .../core/{atlaspack => cli}/bin/atlaspack.js | 0 .../core/{atlaspack => cli}/bin/dev-bin.js | 0 .../{atlaspack => cli}/ensure-no-dev-lib.sh | 0 packages/core/{atlaspack => cli}/package.json | 6 +- .../{atlaspack => cli}/src/.eslintrc.json | 0 packages/core/{atlaspack => cli}/src/bin.js | 0 packages/core/{atlaspack => cli}/src/cli.js | 0 packages/core/integration-tests/package.json | 2 +- .../integration-tests/test/atlaspack-link.js | 123 ++++++++---------- packages/core/integration-tests/test/babel.js | 2 +- .../integration/target-source/package.json | 2 +- .../core/test-utils/test/fsFixture.test.js | 13 +- packages/dev/atlaspack-link/src/link.js | 4 +- packages/examples/eslint-example/package.json | 4 +- packages/examples/html/package.json | 2 +- packages/examples/kitchen-sink/package.json | 4 +- packages/examples/react-hmr/package.json | 2 +- packages/examples/three/package.json | 4 +- 23 files changed, 95 insertions(+), 106 deletions(-) rename packages/core/{atlaspack => cli}/.npmignore (100%) rename packages/core/{atlaspack => cli}/README.md (98%) rename packages/core/{atlaspack => cli}/bin/atlaspack.js (100%) rename packages/core/{atlaspack => cli}/bin/dev-bin.js (100%) rename packages/core/{atlaspack => cli}/ensure-no-dev-lib.sh (100%) rename packages/core/{atlaspack => cli}/package.json (93%) rename packages/core/{atlaspack => cli}/src/.eslintrc.json (100%) rename packages/core/{atlaspack => cli}/src/bin.js (100%) rename packages/core/{atlaspack => cli}/src/cli.js (100%) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8a067a202..1674c0a9e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -61,7 +61,7 @@ jobs: if: ${{ runner.os == 'macOS' && inputs.profile == 'canary' }} run: dsymutil packages/*/*/*.node - name: Upload debug symbols - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ inputs.profile == 'canary' }} with: name: debug-symbols-${{ matrix.name }} @@ -69,7 +69,7 @@ jobs: - name: Strip debug symbols # https://github.com/rust-lang/rust/issues/46034 run: strip -x packages/*/*/*.node # Must use -x on macOS. This produces larger results on linux. - name: Upload artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: bindings-${{ matrix.name }} path: packages/*/*/*.node @@ -85,7 +85,7 @@ jobs: container: image: node:22.4-bullseye steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install Rust uses: actions-rs/toolchain@v1 with: @@ -102,7 +102,7 @@ jobs: find packages -name "*.node" -type f -exec objcopy --strip-debug --strip-unneeded {} \; find packages -name "*.node" -type f -exec objcopy --add-gnu-debuglink={}.debug {} \; - name: Upload debug symbols - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ inputs.profile == 'canary' }} with: name: debug-symbols-linux-gnu-x64 @@ -110,11 +110,11 @@ jobs: - name: Strip debug symbols # https://github.com/rust-lang/rust/issues/46034 run: strip packages/*/*/*.node - name: Upload artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: bindings-linux-gnu-x64 path: packages/*/*/*.node - - name: debug + - name: Debug run: ls -l packages/*/*/*.node - name: Smoke test run: node -e 'require("@atlaspack/rust")' @@ -164,7 +164,7 @@ jobs: find packages -name "*.node" -type f -exec ${{ matrix.objcopy }} --strip-debug --strip-unneeded {} \; find packages -name "*.node" -type f -exec ${{ matrix.objcopy }} --add-gnu-debuglink={}.debug {} \; - name: Upload debug symbols - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ inputs.profile == 'canary' }} with: name: debug-symbols-${{ matrix.target }} @@ -172,16 +172,16 @@ jobs: - name: Strip debug symbols # https://github.com/rust-lang/rust/issues/46034 run: ${{ matrix.strip }} packages/*/*/*.node - name: Upload artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: bindings-${{ matrix.target }} path: packages/*/*/*.node - - name: debug + - name: Debug run: ls -l packages/*/*/*.node - name: Configure binfmt-support run: docker run --rm --privileged multiarch/qemu-user-static:register --reset - name: Smoke test - uses: addnab/docker-run-action@v1 + uses: addnab/docker-run-action@v3 with: image: ghcr.io/devongovett/multiarch-node:node14-${{ matrix.arch }}-focal options: -v ${{github.workspace}}:/work @@ -202,7 +202,7 @@ jobs: - name: Build native packages run: yarn build-native-${{ inputs.profile }} - name: Download artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: artifacts - name: Move bindings @@ -215,14 +215,13 @@ jobs: find artifacts -name "*.node" -path "**/DWARF/**" -exec cp {} debug-symbols/ \; ls -l debug-symbols - name: Upload combined debug symbols artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: ${{ inputs.profile == 'canary' }} with: name: debug-symbols path: debug-symbols/** - name: Debug - run: | - ls -l packages/*/*/*.node + run: ls -l packages/*/*/*.node - run: echo //registry.npmjs.org/:_authToken=${NPM_TOKEN} > .npmrc env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.prettierignore b/.prettierignore index 5e12a29bc..9ba5c3149 100644 --- a/.prettierignore +++ b/.prettierignore @@ -13,4 +13,4 @@ tmp # Ignoring main README for now because generated Table of Contents adds a line that prettier removes # in precommit hook, causing `yarn lint:readme` to fail /README.md -/packages/core/atlaspack/README.md +/packages/core/cli/README.md diff --git a/README.md b/README.md index 0ea8c4ece..998be841a 120000 --- a/README.md +++ b/README.md @@ -1 +1 @@ -./packages/core/atlaspack/README.md \ No newline at end of file +packages/core/cli/README.md \ No newline at end of file diff --git a/packages/core/atlaspack/.npmignore b/packages/core/cli/.npmignore similarity index 100% rename from packages/core/atlaspack/.npmignore rename to packages/core/cli/.npmignore diff --git a/packages/core/atlaspack/README.md b/packages/core/cli/README.md similarity index 98% rename from packages/core/atlaspack/README.md rename to packages/core/cli/README.md index 26345581b..5cbfd1554 100644 --- a/packages/core/atlaspack/README.md +++ b/packages/core/cli/README.md @@ -20,7 +20,7 @@ Special thanks to [Devon](https://github.com/devongovett) for his invaluable con ## Installation ```sh -npm install --save-dev atlaspack +npm install --save-dev @atlaspack/cli ``` ## Usage diff --git a/packages/core/atlaspack/bin/atlaspack.js b/packages/core/cli/bin/atlaspack.js similarity index 100% rename from packages/core/atlaspack/bin/atlaspack.js rename to packages/core/cli/bin/atlaspack.js diff --git a/packages/core/atlaspack/bin/dev-bin.js b/packages/core/cli/bin/dev-bin.js similarity index 100% rename from packages/core/atlaspack/bin/dev-bin.js rename to packages/core/cli/bin/dev-bin.js diff --git a/packages/core/atlaspack/ensure-no-dev-lib.sh b/packages/core/cli/ensure-no-dev-lib.sh similarity index 100% rename from packages/core/atlaspack/ensure-no-dev-lib.sh rename to packages/core/cli/ensure-no-dev-lib.sh diff --git a/packages/core/atlaspack/package.json b/packages/core/cli/package.json similarity index 93% rename from packages/core/atlaspack/package.json rename to packages/core/cli/package.json index f4f46f1c1..c31b13d3d 100644 --- a/packages/core/atlaspack/package.json +++ b/packages/core/cli/package.json @@ -1,5 +1,5 @@ { - "name": "atlaspack", + "name": "@atlaspack/cli", "version": "2.12.0", "description": "Blazing fast, zero configuration web application bundler", "license": "MIT", @@ -10,7 +10,9 @@ "type": "git", "url": "https://github.com/atlassian-labs/atlaspack.git" }, - "bin": "bin/atlaspack.js", + "bin": { + "atlaspack": "bin/atlaspack.js" + }, "main": "lib/bin.js", "source": "src/bin.js", "scripts": { diff --git a/packages/core/atlaspack/src/.eslintrc.json b/packages/core/cli/src/.eslintrc.json similarity index 100% rename from packages/core/atlaspack/src/.eslintrc.json rename to packages/core/cli/src/.eslintrc.json diff --git a/packages/core/atlaspack/src/bin.js b/packages/core/cli/src/bin.js similarity index 100% rename from packages/core/atlaspack/src/bin.js rename to packages/core/cli/src/bin.js diff --git a/packages/core/atlaspack/src/cli.js b/packages/core/cli/src/cli.js similarity index 100% rename from packages/core/atlaspack/src/cli.js rename to packages/core/cli/src/cli.js diff --git a/packages/core/integration-tests/package.json b/packages/core/integration-tests/package.json index d2d24caa5..41c93bafa 100644 --- a/packages/core/integration-tests/package.json +++ b/packages/core/integration-tests/package.json @@ -12,6 +12,7 @@ "test-ci": "yarn test --config .mocharc.ci.json --reporter mocha-multi-reporters --reporter-options configFile=./test/mochareporters.json" }, "devDependencies": { + "@atlaspack/cli": "2.12.0", "@babel/core": "^7.22.11", "@babel/plugin-syntax-class-properties": "^7.12.13", "@babel/plugin-syntax-export-default-from": "^7.22.5", @@ -39,7 +40,6 @@ "lodash": "^4.17.15", "ncp": "^2.0.0", "nib": "^1.1.2", - "atlaspack": "2.12.0", "postcss": "^8.4.5", "postcss-custom-properties": "^12.1.2", "postcss-import": "^14.0.2", diff --git a/packages/core/integration-tests/test/atlaspack-link.js b/packages/core/integration-tests/test/atlaspack-link.js index 6ce23b27a..5a4bb40f2 100644 --- a/packages/core/integration-tests/test/atlaspack-link.js +++ b/packages/core/integration-tests/test/atlaspack-link.js @@ -100,13 +100,13 @@ describe.v2('@atlaspack/link', () => { ); assert.equal( - overlayFS.realpathSync('node_modules/atlaspack'), - path.resolve(__dirname, '../../atlaspack'), + overlayFS.realpathSync('node_modules/@atlaspack/cli'), + path.resolve(__dirname, '../../cli'), ); assert.equal( overlayFS.realpathSync('node_modules/.bin/atlaspack'), - path.resolve(__dirname, '../../atlaspack/src/bin.js'), + path.resolve(__dirname, '../../cli/src/bin.js'), ); }); @@ -115,14 +115,15 @@ describe.v2('@atlaspack/link', () => { app yarn.lock: node_modules - atlaspack + @atlaspack/cli @atlaspack/core package-root core + cli + package.json: ${{name: '@atlaspack/cli'}} + src/bin.js: core/package.json: ${{name: '@atlaspack/core'}} - atlaspack - package.json: ${{name: 'atlaspack'}} - src/bin.js:`; + `; overlayFS.chdir('/app'); @@ -137,16 +138,13 @@ describe.v2('@atlaspack/link', () => { ); assert.equal( - overlayFS.realpathSync('node_modules/atlaspack'), - path.resolve(overlayFS.cwd(), '../package-root/core/atlaspack'), + overlayFS.realpathSync('node_modules/@atlaspack/cli'), + path.resolve(overlayFS.cwd(), '../package-root/core/cli'), ); assert.equal( overlayFS.realpathSync('node_modules/.bin/atlaspack'), - path.resolve( - overlayFS.cwd(), - '../package-root/core/atlaspack/src/bin.js', - ), + path.resolve(overlayFS.cwd(), '../package-root/core/cli/src/bin.js'), ); }); @@ -156,8 +154,9 @@ describe.v2('@atlaspack/link', () => { node_modules .bin/atlaspack: @namespace - atlaspack - atlaspack-core`; + atlaspack-cli + atlaspack-core + `; let cli = createProgram({fs: overlayFS}); await cli('link --namespace @namespace'); @@ -166,7 +165,7 @@ describe.v2('@atlaspack/link', () => { assert.equal( overlayFS.realpathSync('node_modules/.bin/atlaspack'), - path.resolve(__dirname, '../../atlaspack/src/bin.js'), + path.resolve(__dirname, '../../cli/src/bin.js'), ); assert.equal( @@ -180,18 +179,18 @@ describe.v2('@atlaspack/link', () => { ); assert.equal( - overlayFS.realpathSync('node_modules/@namespace/atlaspack'), - path.resolve(__dirname, '../../atlaspack'), + overlayFS.realpathSync('node_modules/@namespace/atlaspack-cli'), + path.resolve(__dirname, '../../cli'), ); assert.equal( - overlayFS.realpathSync('node_modules/atlaspack'), - path.resolve(__dirname, '../../atlaspack'), + overlayFS.realpathSync('node_modules/@atlaspack/cli'), + path.resolve(__dirname, '../../cli'), ); assert.equal( overlayFS.realpathSync('node_modules/.bin/atlaspack'), - path.resolve(__dirname, '../../atlaspack/src/bin.js'), + path.resolve(__dirname, '../../cli/src/bin.js'), ); }); @@ -252,8 +251,9 @@ describe.v2('@atlaspack/link', () => { await fsFixture(overlayFS)` yarn.lock: tools - test/node_modules/atlaspack - test2/node_modules/@atlaspack/core`; + test/node_modules/@atlaspack/cli + test2/node_modules/@atlaspack/core + `; let cli = createProgram({fs: overlayFS}); await cli('link --node-modules-glob "tools/*/node_modules"'); @@ -261,19 +261,19 @@ describe.v2('@atlaspack/link', () => { assert(overlayFS.existsSync('.atlaspack-link')); assert(overlayFS.existsSync('tools/test/node_modules')); - assert(!overlayFS.existsSync('tools/test/node_modules/atlaspack')); + assert(!overlayFS.existsSync('tools/test/node_modules/@atlaspack/cli')); assert(overlayFS.existsSync('tools/test2/node_modules')); assert(!overlayFS.existsSync('tools/test2/node_modules/@atlaspack/core')); assert.equal( - overlayFS.realpathSync('node_modules/atlaspack'), - path.resolve(__dirname, '../../atlaspack'), + overlayFS.realpathSync('node_modules/@atlaspack/cli'), + path.resolve(__dirname, '../../cli'), ); assert.equal( overlayFS.realpathSync('node_modules/.bin/atlaspack'), - path.resolve(__dirname, '../../atlaspack/src/bin.js'), + path.resolve(__dirname, '../../cli/src/bin.js'), ); assert.equal( @@ -286,8 +286,9 @@ describe.v2('@atlaspack/link', () => { await fsFixture(overlayFS)` yarn.lock: node_modules - atlaspack - @atlaspack/core`; + @atlaspack/cli + @atlaspack/core + `; let cli = createProgram({fs: overlayFS}); await cli('link --dry-run'); @@ -300,8 +301,8 @@ describe.v2('@atlaspack/link', () => { ); assert.equal( - overlayFS.realpathSync('node_modules/atlaspack'), - path.resolve('/app/node_modules/atlaspack'), + overlayFS.realpathSync('node_modules/@atlaspack/cli'), + path.resolve('/app/node_modules/@atlaspack/cli'), ); assert(!overlayFS.existsSync('node_modules/.bin/atlaspack')); @@ -354,11 +355,8 @@ describe.v2('@atlaspack/link', () => { await fsFixture(overlayFS)` yarn.lock: node_modules - .bin/atlaspack -> ${path.resolve( - __dirname, - '../../atlaspack/src/bin.js', - )} - atlaspack -> ${path.resolve(__dirname, '../../atlaspack')} + .bin/atlaspack -> ${path.resolve(__dirname, '../../cli/src/bin.js')} + @atlaspack/cli -> ${path.resolve(__dirname, '../../cli')} @atlaspack/core -> ${path.resolve(__dirname, '../../core')} .atlaspack-link: ${{ appRoot: '/app', @@ -368,17 +366,17 @@ describe.v2('@atlaspack/link', () => { }}`; assert(overlayFS.existsSync('.atlaspack-link')); - assert(overlayFS.existsSync('node_modules/@atlaspack/core')); - assert(overlayFS.existsSync('node_modules/atlaspack')); assert(overlayFS.existsSync('node_modules/.bin/atlaspack')); + assert(overlayFS.existsSync('node_modules/@atlaspack/cli')); + assert(overlayFS.existsSync('node_modules/@atlaspack/core')); let cli = createProgram({fs: overlayFS}); await cli('unlink'); assert(!overlayFS.existsSync('.atlaspack-link')); - assert(!overlayFS.existsSync('node_modules/@atlaspack/core')); - assert(!overlayFS.existsSync('node_modules/atlaspack')); assert(!overlayFS.existsSync('node_modules/.bin/atlaspack')); + assert(!overlayFS.existsSync('node_modules/@atlaspack/cli')); + assert(!overlayFS.existsSync('node_modules/@atlaspack/core')); }); it('unlinks from a custom package root', async () => { @@ -390,21 +388,23 @@ describe.v2('@atlaspack/link', () => { nodeModulesGlobs: ['node_modules'], namespace: '@atlaspack', }} - node_modules/atlaspack -> package-root/core/atlaspack + node_modules/.bin/atlaspack -> package-root/core/cli/src/bin.js + node_modules/@atlaspack/cli -> package-root/core/cli node_modules/@atlaspack/core -> package-root/core/core - node_modules/.bin/atlaspack -> package-root/core/atlaspack/src/bin.js`; + `; await fsFixture(overlayFS, '/')` + package-root/core/cli/package.json: ${{name: '@atlaspack/cli'}} + package-root/core/cli/src/bin.js: package-root/core/core/package.json: ${{name: '@atlaspack/core'}} - package-root/core/atlaspack/package.json: ${{name: 'atlaspack'}} - package-root/core/atlaspack/src/bin.js:`; + `; let cli = createProgram({fs: overlayFS}); await cli('unlink'); assert(!overlayFS.existsSync('.atlaspack-link')); + assert(!overlayFS.existsSync('node_modules/@atlaspack/cli')); assert(!overlayFS.existsSync('node_modules/@atlaspack/core')); - assert(!overlayFS.existsSync('node_modules/atlaspack')); assert(!overlayFS.existsSync('node_modules/.bin/atlaspack')); }); @@ -418,12 +418,9 @@ describe.v2('@atlaspack/link', () => { namespace: '@namespace', }} node_modules - .bin/atlaspack -> ${path.resolve( - __dirname, - '../../atlaspack/src/bin.js', - )} - atlaspack -> ${path.resolve(__dirname, '../../atlaspack')} - @namespace/atlaspack -> ${path.resolve(__dirname, '../../atlaspack')} + .bin/atlaspack -> ${path.resolve(__dirname, '../../cli/src/bin.js')} + atlaspack/cli -> ${path.resolve(__dirname, '../../cli')} + @namespace/atlaspack-cli -> ${path.resolve(__dirname, '../../cli')} atlaspack/core -> ${path.resolve(__dirname, '../../core')} @namespace/atlaspack-core -> ${path.resolve( __dirname, @@ -435,10 +432,10 @@ describe.v2('@atlaspack/link', () => { assert(!overlayFS.existsSync('.atlaspack-link')); assert(!overlayFS.existsSync('node_modules/@atlaspack/core')); - assert(!overlayFS.existsSync('node_modules/atlaspack')); + assert(!overlayFS.existsSync('node_modules/@atlaspack/cli')); assert(!overlayFS.existsSync('node_modules/.bin/atlaspack')); assert(!overlayFS.existsSync('node_modules/@namespace/atlaspack-core')); - assert(!overlayFS.existsSync('node_modules/@namespace/atlaspack')); + assert(!overlayFS.existsSync('node_modules/@namespace/atlaspack-cli')); }); // FIXME: this test fails on windows @@ -509,12 +506,9 @@ describe.v2('@atlaspack/link', () => { namespace: '@atlaspack', }} node_modules - atlaspack -> ${path.resolve(__dirname, '../../atlaspack')} + .bin/atlaspack -> ${path.resolve(__dirname, '../../cli/src/bin.js')} + @atlaspack/cli -> ${path.resolve(__dirname, '../../cli')} @atlaspack/core -> ${path.resolve(__dirname, '../../core')} - .bin/atlaspack -> ${path.resolve( - __dirname, - '../../atlaspack/src/bin.js', - )} tools test/node_modules/atlaspack -> ${path.resolve( __dirname, @@ -540,11 +534,8 @@ describe.v2('@atlaspack/link', () => { await fsFixture(overlayFS)` yarn.lock: node_modules - .bin/atlaspack -> ${path.resolve( - __dirname, - '../../atlaspack/src/bin.js', - )} - atlaspack -> ${path.resolve(__dirname, '../../atlaspack')} + .bin/atlaspack -> ${path.resolve(__dirname, '../../cli/src/bin.js')} + @atlaspack/cli -> ${path.resolve(__dirname, '../../cli')} @atlaspack/core -> ${path.resolve(__dirname, '../../core')} .atlaspack-link: ${{ appRoot: '/app', @@ -565,13 +556,13 @@ describe.v2('@atlaspack/link', () => { ); assert.equal( - overlayFS.realpathSync('node_modules/atlaspack'), - path.resolve(__dirname, '../../atlaspack'), + overlayFS.realpathSync('node_modules/@atlaspack/cli'), + path.resolve(__dirname, '../../cli'), ); assert.equal( overlayFS.realpathSync('node_modules/.bin/atlaspack'), - path.resolve(__dirname, '../../atlaspack/src/bin.js'), + path.resolve(__dirname, '../../cli/src/bin.js'), ); }); }); diff --git a/packages/core/integration-tests/test/babel.js b/packages/core/integration-tests/test/babel.js index 3beb0dbdc..7f1c13a61 100644 --- a/packages/core/integration-tests/test/babel.js +++ b/packages/core/integration-tests/test/babel.js @@ -21,7 +21,7 @@ import {spawnSync} from 'child_process'; import tempy from 'tempy'; import {md} from '@atlaspack/diagnostic'; -const atlaspackCli = require.resolve('atlaspack/src/bin.js'); +const atlaspackCli = require.resolve('@atlaspack/cli/src/bin.js'); const inputDir = path.join(__dirname, '/input'); describe.v2('babel', function () { diff --git a/packages/core/integration-tests/test/integration/target-source/package.json b/packages/core/integration-tests/test/integration/target-source/package.json index 33fc5621b..6c0596881 100644 --- a/packages/core/integration-tests/test/integration/target-source/package.json +++ b/packages/core/integration-tests/test/integration/target-source/package.json @@ -7,7 +7,7 @@ "scripts": { "clean": "rm -rf ../.atlaspack-cache dist", "demo": "yarn clean && ATLASPACK_WORKERS=0 atlaspack build packages/package-a", - "debug": "yarn clean && ATLASPACK_WORKERS=0 node --inspect-brk ../../core/atlaspack/src/bin.js build packages/*", + "debug": "yarn clean && ATLASPACK_WORKERS=0 node --inspect-brk ../../core/cli/src/bin.js build packages/*", "watch": "nodemon -w ../../ -i packages/package-a/dist -i packages/package-b/dist -i ../.atlaspack-cache -d 2 -x yarn demo" } } diff --git a/packages/core/test-utils/test/fsFixture.test.js b/packages/core/test-utils/test/fsFixture.test.js index f13290ecc..92b1864e0 100644 --- a/packages/core/test-utils/test/fsFixture.test.js +++ b/packages/core/test-utils/test/fsFixture.test.js @@ -526,12 +526,9 @@ describe('fsFixture', () => { yarn.lock: node_modules .bin - atlaspack -> ${path.resolve( - __dirname, - '../../atlaspack/src/bin.js', - )} - atlaspack -> ${path.resolve(__dirname, '../../atlaspack')} + atlaspack -> ${path.resolve(__dirname, '../../cli/src/bin.js')} @atlaspack + cli -> ${path.resolve(__dirname, '../../cli')} core -> ${path.resolve(__dirname, '../../core')} .atlaspackrc: ${{ extends: '@atlaspack/config-default', @@ -555,12 +552,12 @@ describe('fsFixture', () => { assert.equal( fs.realpathSync('/app/node_modules/.bin/atlaspack'), - path.resolve(__dirname, '../../atlaspack/src/bin.js'), + path.resolve(__dirname, '../../cli/src/bin.js'), ); assert.equal( - fs.realpathSync('/app/node_modules/atlaspack'), - path.resolve(__dirname, '../../atlaspack'), + fs.realpathSync('/app/node_modules/@atlaspack/cli'), + path.resolve(__dirname, '../../cli'), ); assert.equal( diff --git a/packages/dev/atlaspack-link/src/link.js b/packages/dev/atlaspack-link/src/link.js index 4033a7913..7a19e9d85 100644 --- a/packages/dev/atlaspack-link/src/link.js +++ b/packages/dev/atlaspack-link/src/link.js @@ -67,11 +67,11 @@ export async function link( await fsSymlink(p, path.join(appRoot, 'node_modules', packageName), opts); } - // Step 4: Point `atlaspack` bin symlink to linked `packages/core/atlaspack/src/bin.js` + // Step 4: Point `atlaspack` bin symlink to linked `packages/core/cli/src/bin.js` // -------------------------------------------------------------------------------- await fsSymlink( - path.join(packageRoot, 'core/atlaspack/src/bin.js'), + path.join(packageRoot, 'core/cli/src/bin.js'), path.join(appRoot, 'node_modules/.bin/atlaspack'), opts, ); diff --git a/packages/examples/eslint-example/package.json b/packages/examples/eslint-example/package.json index f0601de58..c40a77053 100644 --- a/packages/examples/eslint-example/package.json +++ b/packages/examples/eslint-example/package.json @@ -19,8 +19,8 @@ "devDependencies": { "@babel/core": "^7.22.11", "@atlaspack/babel-register": "2.12.0", + "@atlaspack/cli": "2.12.0", "@atlaspack/core": "2.12.0", - "@atlaspack/validator-eslint": "2.12.0", - "atlaspack": "2.12.0" + "@atlaspack/validator-eslint": "2.12.0" } } diff --git a/packages/examples/html/package.json b/packages/examples/html/package.json index 7426ee181..f8487d8a3 100644 --- a/packages/examples/html/package.json +++ b/packages/examples/html/package.json @@ -14,7 +14,7 @@ "devDependencies": { "@babel/core": "^7.22.11", "@atlaspack/babel-register": "2.12.0", - "atlaspack": "2.12.0" + "@atlaspack/cli": "2.12.0" }, "dependencies": { "lodash": "^4.17.11", diff --git a/packages/examples/kitchen-sink/package.json b/packages/examples/kitchen-sink/package.json index 81c7b6dc7..865448061 100644 --- a/packages/examples/kitchen-sink/package.json +++ b/packages/examples/kitchen-sink/package.json @@ -10,11 +10,11 @@ "devDependencies": { "@babel/core": "^7.22.11", "@atlaspack/babel-register": "2.12.0", + "@atlaspack/cli": "2.12.0", "@atlaspack/config-default": "2.12.0", "@atlaspack/core": "2.12.0", "@atlaspack/optimizer-esbuild": "2.12.0", - "@atlaspack/reporter-sourcemap-visualiser": "2.12.0", - "atlaspack": "2.12.0" + "@atlaspack/reporter-sourcemap-visualiser": "2.12.0" }, "targets": { "browserModern": { diff --git a/packages/examples/react-hmr/package.json b/packages/examples/react-hmr/package.json index 854d133ba..2b32f57ec 100644 --- a/packages/examples/react-hmr/package.json +++ b/packages/examples/react-hmr/package.json @@ -7,7 +7,7 @@ "demo": "atlaspack serve src/index.html --no-cache --https" }, "devDependencies": { - "atlaspack": "2.12.0" + "@atlaspack/cli": "2.12.0" }, "targets": { "browserModern": { diff --git a/packages/examples/three/package.json b/packages/examples/three/package.json index e0b8eaddc..cb7c774bd 100644 --- a/packages/examples/three/package.json +++ b/packages/examples/three/package.json @@ -27,9 +27,9 @@ } }, "devDependencies": { + "@atlaspack/cli": "2.12.0", "@atlaspack/config-default": "2.12.0", "@atlaspack/core": "2.12.0", - "@atlaspack/optimizer-esbuild": "2.12.0", - "atlaspack": "2.12.0" + "@atlaspack/optimizer-esbuild": "2.12.0" } } From d2ae8a8bf0ed4e6dd7dadbe8764b39a17e2187d9 Mon Sep 17 00:00:00 2001 From: Pedro Tacla Yamada Date: Tue, 20 Aug 2024 14:03:21 +1000 Subject: [PATCH 2/3] Remove dashmap (#10) --- .gitignore | 1 + CODE_OF_CONDUCT.md | 14 ++--- CONTRIBUTING.md | 10 ++-- Cargo.lock | 9 +-- crates/atlaspack_filesystem/Cargo.toml | 1 - crates/atlaspack_filesystem/src/lib.rs | 7 +-- .../src/os_file_system/canonicalize.rs | 16 +++-- crates/node-bindings/Cargo.toml | 1 - packages/utils/dev-dep-resolver/Cargo.toml | 2 +- packages/utils/dev-dep-resolver/src/lib.rs | 48 +++++++++------ packages/utils/node-resolver-rs/Cargo.toml | 1 - packages/utils/node-resolver-rs/src/cache.rs | 58 +++++++++++++------ 12 files changed, 99 insertions(+), 69 deletions(-) diff --git a/.gitignore b/.gitignore index aa6a405ca..4ce5bfb5c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .idea/ .nyc_output/ .atlaspack-cache/ +.parcel-cache/ .vscode/* !.vscode/extensions.json coverage/ diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index c048a940b..139534425 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -6,13 +6,13 @@ We are committed to making participation in this project a harassment-free exper Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery -* Personal attacks -* Trolling or insulting/derogatory comments -* Public or private harassment -* Publishing other's private information, such as physical or electronic addresses, without explicit permission -* Submitting contributions or comments that you know to violate the intellectual property or privacy rights of others -* Other unethical or unprofessional conduct +- The use of sexualized language or imagery +- Personal attacks +- Trolling or insulting/derogatory comments +- Public or private harassment +- Publishing other's private information, such as physical or electronic addresses, without explicit permission +- Submitting contributions or comments that you know to violate the intellectual property or privacy rights of others +- Other unethical or unprofessional conduct Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 463176c87..3cb951a8a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,9 +6,9 @@ Thank you for considering a contribution to Atlaspack! Unfortunately pull reques For pull requests, please: -* Add tests for new features and bug fixes -* Follow the existing style -* Separate unrelated changes into multiple pull requests +- Add tests for new features and bug fixes +- Follow the existing style +- Separate unrelated changes into multiple pull requests See the existing issues for things to start contributing. @@ -18,5 +18,5 @@ Atlassian requires contributors to sign a Contributor License Agreement, known a Prior to accepting your contributions we ask that you please follow the appropriate link below to digitally sign the CLA. The Corporate CLA is for those who are contributing as a member of an organization and the individual CLA is for those contributing as an individual. -* [CLA for corporate contributors](https://opensource.atlassian.com/corporate) -* [CLA for individuals](https://opensource.atlassian.com/individual) +- [CLA for corporate contributors](https://opensource.atlassian.com/corporate) +- [CLA for individuals](https://opensource.atlassian.com/individual) diff --git a/Cargo.lock b/Cargo.lock index 252baf210..562b6ff27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -153,11 +153,11 @@ name = "atlaspack-dev-dep-resolver" version = "0.1.0" dependencies = [ "atlaspack-resolver", - "dashmap", "es-module-lexer", "glob", "rayon", "serde_json", + "xxhash-rust", ] [[package]] @@ -221,7 +221,6 @@ dependencies = [ "atlaspack_package_manager", "atlaspack_plugin_transformer_js", "crossbeam-channel", - "dashmap", "getrandom", "glob", "indexmap 1.9.3", @@ -258,7 +257,6 @@ dependencies = [ "atlaspack_filesystem", "bitflags 1.3.2", "criterion", - "dashmap", "glob-match", "indexmap 1.9.3", "is_elevated", @@ -347,7 +345,6 @@ version = "0.1.0" dependencies = [ "anyhow", "assert_fs", - "dashmap", "is_elevated", "mockall", "xxhash-rust", @@ -5034,9 +5031,9 @@ dependencies = [ [[package]] name = "xxhash-rust" -version = "0.8.10" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927da81e25be1e1a2901d59b81b37dd2efd1fc9c9345a55007f09bf5a2d3ee03" +checksum = "6a5cbf750400958819fb6178eaa83bee5cd9c29a26a40cc241df8c70fdd46984" [[package]] name = "zerocopy" diff --git a/crates/atlaspack_filesystem/Cargo.toml b/crates/atlaspack_filesystem/Cargo.toml index 072323c4c..f5ef01362 100644 --- a/crates/atlaspack_filesystem/Cargo.toml +++ b/crates/atlaspack_filesystem/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" description = "FileSystem wrapper trait for use in Atlaspack codebase." [dependencies] -dashmap = "5.5.3" mockall = "0.12.1" xxhash-rust = { version = "0.8.2", features = ["xxh3"] } anyhow = "1.0.86" diff --git a/crates/atlaspack_filesystem/src/lib.rs b/crates/atlaspack_filesystem/src/lib.rs index 38f8370ee..72ccfaa3b 100644 --- a/crates/atlaspack_filesystem/src/lib.rs +++ b/crates/atlaspack_filesystem/src/lib.rs @@ -1,8 +1,7 @@ +use std::collections::HashMap; use std::path::Path; use std::path::PathBuf; -use std::sync::Arc; - -use dashmap::DashMap; +use std::sync::{Arc, RwLock}; /// In-memory file-system for testing pub mod in_memory_file_system; @@ -18,7 +17,7 @@ pub mod os_file_system; pub type FileSystemRef = Arc; pub type FileSystemRealPathCache = - DashMap, xxhash_rust::xxh3::Xxh3Builder>; + RwLock, xxhash_rust::xxh3::Xxh3Builder>>; /// Trait abstracting file-system operations /// . diff --git a/crates/atlaspack_filesystem/src/os_file_system/canonicalize.rs b/crates/atlaspack_filesystem/src/os_file_system/canonicalize.rs index 110d4aec9..33a57358e 100644 --- a/crates/atlaspack_filesystem/src/os_file_system/canonicalize.rs +++ b/crates/atlaspack_filesystem/src/os_file_system/canonicalize.rs @@ -28,21 +28,27 @@ pub fn canonicalize(path: &Path, cache: &FileSystemRealPathCache) -> std::io::Re ret.push(c); // First, check the cache for the path up to this point. - let link = if let Some(cached) = cache.get(&ret) { - if let Some(link) = &*cached { - link.clone() + let read = cache.read().unwrap(); + let cached = read.get(&ret).cloned(); + drop(read); + let link = if let Some(cached) = cached { + if let Some(link) = cached { + link } else { continue; } } else { let stat = std::fs::symlink_metadata(&ret)?; if !stat.is_symlink() { - cache.insert(ret.clone(), None); + cache.write().unwrap().insert(ret.clone(), None); continue; } let link = std::fs::read_link(&ret)?; - cache.insert(ret.clone(), Some(link.clone())); + cache + .write() + .unwrap() + .insert(ret.clone(), Some(link.clone())); link }; diff --git a/crates/node-bindings/Cargo.toml b/crates/node-bindings/Cargo.toml index bc414c226..4d61aeaa9 100644 --- a/crates/node-bindings/Cargo.toml +++ b/crates/node-bindings/Cargo.toml @@ -22,7 +22,6 @@ atlaspack_plugin_transformer_js = { path = "../atlaspack_plugin_transformer_js" atlaspack_napi_helpers = { path = "../atlaspack_napi_helpers" } anyhow = "1.0.82" -dashmap = "5.4.0" glob = "0.3.1" log = "0.4.21" mockall = "0.12.1" diff --git a/packages/utils/dev-dep-resolver/Cargo.toml b/packages/utils/dev-dep-resolver/Cargo.toml index e96ef4d2e..2e23a7978 100644 --- a/packages/utils/dev-dep-resolver/Cargo.toml +++ b/packages/utils/dev-dep-resolver/Cargo.toml @@ -9,5 +9,5 @@ atlaspack-resolver = { path = "../node-resolver-rs" } es-module-lexer = { git = "https://github.com/devongovett/es-module-lexer" } serde_json = "1.0.91" rayon = "1.7.0" -dashmap = "5.4.0" glob = "0.3.1" +xxhash-rust = "0.8.12" diff --git a/packages/utils/dev-dep-resolver/src/lib.rs b/packages/utils/dev-dep-resolver/src/lib.rs index 0a31d70c0..35583dc04 100644 --- a/packages/utils/dev-dep-resolver/src/lib.rs +++ b/packages/utils/dev-dep-resolver/src/lib.rs @@ -1,7 +1,9 @@ use std::borrow::Cow; +use std::collections::{HashMap, HashSet}; use std::path::Component; use std::path::Path; use std::path::PathBuf; +use std::sync::{Arc, RwLock}; use atlaspack_resolver::CacheCow; use atlaspack_resolver::Invalidations; @@ -13,8 +15,6 @@ use atlaspack_resolver::ResolverError; use atlaspack_resolver::Specifier; use atlaspack_resolver::SpecifierError; use atlaspack_resolver::SpecifierType; -use dashmap::DashMap; -use dashmap::DashSet; use es_module_lexer::lex; use es_module_lexer::ImportKind; // use rayon::prelude::{ParallelBridge, ParallelIterator}; @@ -68,12 +68,12 @@ impl From for EsmGraphBuilderError { #[derive(Default)] pub struct Cache { - entries: DashMap, + entries: RwLock, xxhash_rust::xxh3::Xxh3Builder>>, } struct EsmGraphBuilder<'a> { - visited: DashSet, - visited_globs: DashSet, + visited: RwLock>, + visited_globs: RwLock>, invalidations: Invalidations, cjs_resolver: Resolver<'a>, esm_resolver: Resolver<'a>, @@ -82,11 +82,11 @@ struct EsmGraphBuilder<'a> { impl<'a> EsmGraphBuilder<'a> { pub fn build(&self, file: &Path) -> Result<(), EsmGraphBuilderError> { - if self.visited.contains(file) { + if self.visited.read().unwrap().contains(file) { return Ok(()); } - self.visited.insert(file.to_owned()); + self.visited.write().unwrap().insert(file.to_owned()); if let Some(ext) = file.extension() { if ext != "js" && ext != "cjs" && ext != "mjs" { @@ -95,14 +95,15 @@ impl<'a> EsmGraphBuilder<'a> { } } - if let Some(invalidations) = self.cache.entries.get(file) { + let read = self.cache.entries.read().unwrap(); + let value = read.get(file).cloned(); + drop(read); + if let Some(invalidations) = value { self.invalidations.extend(&invalidations); - for p in invalidations - .invalidate_on_file_change - .read() - .unwrap() - .iter() - { + let read = invalidations.invalidate_on_file_change.read().unwrap(); + let paths: Vec = read.iter().cloned().collect(); + drop(read); + for p in paths { self.build(&p)?; } return Ok(()); @@ -168,7 +169,12 @@ impl<'a> EsmGraphBuilder<'a> { .collect::>()?; self.invalidations.extend(&invalidations); - self.cache.entries.insert(file.to_owned(), invalidations); + self + .cache + .entries + .write() + .unwrap() + .insert(file.to_owned(), Arc::new(invalidations)); Ok(()) } @@ -207,11 +213,15 @@ impl<'a> EsmGraphBuilder<'a> { // Invalidate when new files match the glob. invalidations.invalidate_on_glob_create(pattern.to_string_lossy()); - if self.visited_globs.contains(&pattern) { + if self.visited_globs.read().unwrap().contains(&pattern) { return Ok(()); } - self.visited_globs.insert(pattern.to_path_buf()); + self + .visited_globs + .write() + .unwrap() + .insert(pattern.to_path_buf()); for path in glob::glob(pattern.to_string_lossy().as_ref())? { let path = path?; @@ -500,8 +510,8 @@ pub fn build_esm_graph( cache: &Cache, ) -> Result { let visitor = EsmGraphBuilder { - visited: DashSet::new(), - visited_globs: DashSet::new(), + visited: RwLock::new(HashSet::new()), + visited_globs: RwLock::new(HashSet::new()), invalidations: Invalidations::default(), cjs_resolver: Resolver::node( Cow::Borrowed(project_root), diff --git a/packages/utils/node-resolver-rs/Cargo.toml b/packages/utils/node-resolver-rs/Cargo.toml index d8a88a0a3..1cd8d2611 100644 --- a/packages/utils/node-resolver-rs/Cargo.toml +++ b/packages/utils/node-resolver-rs/Cargo.toml @@ -13,7 +13,6 @@ atlaspack_core = { path = "../../../crates/atlaspack_core" } atlaspack_filesystem = { path = "../../../crates/atlaspack_filesystem" } bitflags = "1.3.2" -dashmap = "5.4.0" glob-match = "0.2.1" indexmap = { version = "1.9.2", features = ["serde"] } itertools = "0.10.5" diff --git a/packages/utils/node-resolver-rs/src/cache.rs b/packages/utils/node-resolver-rs/src/cache.rs index e68ece170..62485f7cc 100644 --- a/packages/utils/node-resolver-rs/src/cache.rs +++ b/packages/utils/node-resolver-rs/src/cache.rs @@ -1,11 +1,10 @@ use std::borrow::Cow; +use std::collections::HashMap; use std::fmt; use std::ops::Deref; use std::path::Path; use std::path::PathBuf; -use std::sync::Arc; - -use dashmap::DashMap; +use std::sync::{Arc, RwLock}; use atlaspack_core::types::File; use atlaspack_filesystem::{FileSystemRealPathCache, FileSystemRef}; @@ -24,12 +23,13 @@ pub struct Cache { /// way to associate a lifetime with owned data stored in the same struct. We only vend temporary references /// from our public methods so this is ok for now. FrozenMap is an append only map, which doesn't require &mut /// to insert into. Since each value is in a Box, it won't move and therefore references are stable. - packages: DashMap, ResolverError>>, DefaultHasher>, - tsconfigs: DashMap, ResolverError>>, DefaultHasher>, + packages: RwLock, ResolverError>>, DefaultHasher>>, + tsconfigs: + RwLock, ResolverError>>, DefaultHasher>>, // In particular just the is_dir_cache spends around 8% of the time on a large project resolution // hashing paths. Instead of using a hashmap we should try a trie here. - is_dir_cache: DashMap, - is_file_cache: DashMap, + is_dir_cache: RwLock>, + is_file_cache: RwLock>, realpath_cache: FileSystemRealPathCache, } @@ -92,31 +92,39 @@ impl Cache { pub fn new(fs: FileSystemRef) -> Self { Self { fs, - packages: DashMap::with_hasher(DefaultHasher::default()), - tsconfigs: DashMap::with_hasher(DefaultHasher::default()), - is_file_cache: DashMap::with_hasher(DefaultHasher::default()), - is_dir_cache: DashMap::with_hasher(DefaultHasher::default()), + packages: RwLock::new(HashMap::with_hasher(DefaultHasher::default())), + tsconfigs: RwLock::new(HashMap::with_hasher(DefaultHasher::default())), + is_file_cache: RwLock::new(HashMap::with_hasher(DefaultHasher::default())), + is_dir_cache: RwLock::new(HashMap::with_hasher(DefaultHasher::default())), realpath_cache: FileSystemRealPathCache::default(), } } pub fn is_file(&self, path: &Path) -> bool { - if let Some(is_file) = self.is_file_cache.get(path) { + if let Some(is_file) = self.is_file_cache.read().unwrap().get(path) { return *is_file; } let is_file = self.fs.is_file(path); - self.is_file_cache.insert(path.to_path_buf(), is_file); + self + .is_file_cache + .write() + .unwrap() + .insert(path.to_path_buf(), is_file); is_file } pub fn is_dir(&self, path: &Path) -> bool { - if let Some(is_file) = self.is_dir_cache.get(path) { + if let Some(is_file) = self.is_dir_cache.read().unwrap().get(path) { return *is_file; } let is_file = self.fs.is_dir(path); - self.is_dir_cache.insert(path.to_path_buf(), is_file); + self + .is_dir_cache + .write() + .unwrap() + .insert(path.to_path_buf(), is_file); is_file } @@ -125,9 +133,11 @@ impl Cache { } pub fn read_package(&self, path: Cow) -> Arc, ResolverError>> { - if let Some(pkg) = self.packages.get(path.as_ref()) { + let read = self.packages.read().unwrap(); + if let Some(pkg) = read.get(path.as_ref()) { return pkg.clone(); } + drop(read); fn read_package<'a>( fs: &'a FileSystemRef, @@ -170,7 +180,11 @@ impl Cache { // Since we have exclusive access to packages, let entry = Arc::new(package.map(|pkg| Arc::new(pkg))); - let _ = self.packages.insert(path.clone(), entry.clone()); + let _ = self + .packages + .write() + .unwrap() + .insert(path.clone(), entry.clone()); entry.clone() } @@ -180,9 +194,11 @@ impl Cache { path: &Path, process: F, ) -> Arc, ResolverError>> { - if let Some(tsconfig) = self.tsconfigs.get(path) { + let read = self.tsconfigs.read().unwrap(); + if let Some(tsconfig) = read.get(path) { return tsconfig.clone(); } + drop(read); fn read_tsconfig<'a, F: FnOnce(&mut TsConfigWrapper) -> Result<(), ResolverError>>( fs: &FileSystemRef, @@ -207,7 +223,11 @@ impl Cache { // after insert let tsconfig = read_tsconfig(&self.fs, path, process).map(|t| Arc::new(t)); let tsconfig = Arc::new(tsconfig); - let _ = self.tsconfigs.insert(PathBuf::from(path), tsconfig.clone()); + let _ = self + .tsconfigs + .write() + .unwrap() + .insert(PathBuf::from(path), tsconfig.clone()); tsconfig } From 0d6dfc872a28c25385e61988961edd8b57d57050 Mon Sep 17 00:00:00 2001 From: Monica Date: Tue, 20 Aug 2024 14:33:12 +1000 Subject: [PATCH 3/3] Remove upload in unit tests (#17) --- .github/workflows/ci.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f140db01f..fb889735e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,15 +73,6 @@ jobs: - run: yarn --frozen-lockfile - run: yarn build-native-release - run: yarn test:unit - - name: Upload @atlaspack/rust artifacts on Linux with Node v20 - if: ${{ runner.os == 'Linux' && matrix.node == 20 }} - uses: actions/upload-artifact@v3 - with: - name: Rust Linux Binaries - path: | - packages/core/rust/index.d.ts - packages/core/rust/index.js - packages/core/rust/*.node integration_tests: name: Integration tests (${{ matrix.version == 'v3' && 'v3, ' || '' }}${{ matrix.os }}, Node ${{ matrix.node }})