From 44dca3dd135d93526352f81ed2ba81fce7daaa58 Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Wed, 12 Jan 2022 16:09:19 +0200 Subject: [PATCH 1/2] Switch to GitHub Actions CI and tweak README.md --- .github/workflows/ci.yml | 35 +++++++++++++++++++++++++++++++++++ .travis.yml | 5 ----- readme.md | 22 +++++++++++----------- 3 files changed, 46 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/ci.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..b2e67d8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,35 @@ +name: CI + +on: + push: + pull_request: + workflow_dispatch: + +env: + FORCE_COLOR: 2 + +jobs: + test: + name: Node ${{ matrix.node }} on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + node: [6, 8, 10, 12, 14, 16] + os: [ubuntu-latest, windows-latest] + + steps: + - name: Clone repository + uses: actions/checkout@v2 + + - name: Set up Node.js + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node }} + + - name: Install npm dependencies + run: npm install + + - name: Run tests + run: npm test diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 2ae9d62..0000000 --- a/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: node_js -node_js: - - '10' - - '8' - - '6' diff --git a/readme.md b/readme.md index e57de2a..ef3bbf0 100644 --- a/readme.md +++ b/readme.md @@ -1,12 +1,12 @@ -# bin-wrapper [![Build Status](https://travis-ci.org/kevva/bin-wrapper.svg?branch=master)](https://travis-ci.org/kevva/bin-wrapper) +# bin-wrapper [![CI](https://github.com/kevva/bin-wrapper/actions/workflows/ci.yml/badge.svg)](https://github.com/kevva/bin-wrapper/actions/workflows/ci.yml) > Binary wrapper that makes your programs seamlessly available as local dependencies ## Install -``` -$ npm install bin-wrapper +```sh +npm install bin-wrapper ``` @@ -15,7 +15,7 @@ $ npm install bin-wrapper ```js const BinWrapper = require('bin-wrapper'); -const base = 'https://github.com/imagemin/gifsicle-bin/raw/master/vendor'; +const base = 'https://github.com/imagemin/gifsicle-bin/raw/main/vendor'; const bin = new BinWrapper() .src(`${base}/macos/gifsicle`, 'darwin') .src(`${base}/linux/x64/gifsicle`, 'linux', 'x64') @@ -50,15 +50,15 @@ Type: `Object` ##### skipCheck -Type: `boolean`
-Default: `false` +* Type: `boolean` +* Default: `false` Whether to skip the binary check or not. ##### strip -Type: `number`
-Default: `1` +* Type: `number` +* Default: `1` Strip a number of leading paths from file names on extraction. @@ -110,7 +110,7 @@ Returns the full path to your binary. Type: `string` -Define a [semver range](https://github.com/isaacs/node-semver#ranges) to check +Define a [semver range](https://github.com/npm/node-semver#ranges) to check the binary against. ### .run([arguments]) @@ -120,8 +120,8 @@ using the URL provided in `.src()`. #### arguments -Type: `Array`
-Default: `['--version']` +* Type: `Array` +* Default: `['--version']` Command to run the binary with. If it exits with code `0` it means that the binary is working. From 4bc5c9e86e49a2a7d1453146f8b2688b71b2b38d Mon Sep 17 00:00:00 2001 From: XhmikosR Date: Wed, 12 Jan 2022 16:53:07 +0200 Subject: [PATCH 2/2] Update all the stuff, switch to ESM, require Node.js 12 Also, add coverage with c8 --- .github/workflows/ci.yml | 8 +++--- .gitignore | 1 + index.js | 62 +++++++++++++--------------------------- package.json | 39 ++++++++++++++++--------- readme.md | 3 +- test.js | 55 +++++++++++++++++++---------------- 6 files changed, 83 insertions(+), 85 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b2e67d8..79fb78d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,15 +16,15 @@ jobs: strategy: fail-fast: false matrix: - node: [6, 8, 10, 12, 14, 16] + node: [12, 14, 16, 18] os: [ubuntu-latest, windows-latest] steps: - name: Clone repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Set up Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node }} @@ -32,4 +32,4 @@ jobs: run: npm install - name: Run tests - run: npm test + run: npm run test-ci diff --git a/.gitignore b/.gitignore index 239ecff..9eb6759 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules yarn.lock +/coverage diff --git a/index.js b/index.js index 1aba001..7639e0d 100644 --- a/index.js +++ b/index.js @@ -1,17 +1,9 @@ -'use strict'; -const fs = require('fs'); -const path = require('path'); -const url = require('url'); -const pify = require('pify'); -const importLazy = require('import-lazy')(require); - -const binCheck = importLazy('bin-check'); -const binVersionCheck = importLazy('bin-version-check'); -const download = importLazy('download'); -const osFilterObj = importLazy('os-filter-obj'); - -const statAsync = pify(fs.stat); -const chmodAsync = pify(fs.chmod); +import {promises as fs} from 'node:fs'; +import path from 'node:path'; +import binCheck from 'bin-check'; +import binVersionCheck from 'bin-version-check'; +import download from 'download'; +import osFilterObject from 'os-filter-obj'; /** * Initialize a new `BinWrapper` @@ -19,7 +11,7 @@ const chmodAsync = pify(fs.chmod); * @param {Object} options * @api public */ -module.exports = class BinWrapper { +export default class BinWrapper { constructor(options = {}) { this.options = options; @@ -47,7 +39,7 @@ module.exports = class BinWrapper { this._src.push({ url: src, os, - arch + arch, }); return this; @@ -138,8 +130,6 @@ module.exports = class BinWrapper { if (this.version()) { return binVersionCheck(this.path(), this.version()); } - - return Promise.resolve(); }); } @@ -149,12 +139,12 @@ module.exports = class BinWrapper { * @api private */ findExisting() { - return statAsync(this.path()).catch(error => { + return fs.stat(this.path()).catch(error => { if (error && error.code === 'ENOENT') { return this.download(); } - return Promise.reject(error); + throw error; }); } @@ -164,45 +154,33 @@ module.exports = class BinWrapper { * @api private */ download() { - const files = osFilterObj(this.src() || []); - const urls = []; + const files = osFilterObject(this.src() || []); if (files.length === 0) { return Promise.reject(new Error('No binary found matching your system. It\'s probably not supported.')); } - files.forEach(file => urls.push(file.url)); + const urls = []; + for (const file of files) { + urls.push(file.url); + } return Promise.all(urls.map(url => download(url, this.dest(), { extract: true, - strip: this.options.strip + strip: this.options.strip, }))).then(result => { - const resultingFiles = flatten(result.map((item, index) => { + const resultingFiles = result.flatMap((item, index) => { if (Array.isArray(item)) { return item.map(file => file.path); } - const parsedUrl = url.parse(files[index].url); + const parsedUrl = new URL(files[index].url); const parsedPath = path.parse(parsedUrl.pathname); return parsedPath.base; - })); + }); - return Promise.all(resultingFiles.map(fileName => { - return chmodAsync(path.join(this.dest(), fileName), 0o755); - })); + return Promise.all(resultingFiles.map(fileName => fs.chmod(path.join(this.dest(), fileName), 0o755))); }); } -}; - -function flatten(arr) { - return arr.reduce((acc, elem) => { - if (Array.isArray(elem)) { - acc.push(...elem); - } else { - acc.push(elem); - } - - return acc; - }, []); } diff --git a/package.json b/package.json index e49e305..4176148 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,18 @@ "url": "https://github.com/kevva" }, "engines": { - "node": ">=6" + "node": "^12.20.0 || ^14.14.0 || >=16.0.0" }, "scripts": { - "test": "xo && ava" + "ava": "ava", + "xo": "xo", + "test": "npm run xo && npm run ava", + "test-ci": "npm run xo && c8 ava" + }, + "main": "index.js", + "type": "module", + "exports": { + ".": "./index.js" }, "files": [ "index.js" @@ -24,21 +32,26 @@ "local", "wrapper" ], + "c8": { + "reporter": [ + "lcovonly", + "text" + ] + }, "dependencies": { "bin-check": "^4.1.0", - "bin-version-check": "^4.0.0", - "download": "^7.1.0", - "import-lazy": "^3.1.0", - "os-filter-obj": "^2.0.0", - "pify": "^4.0.1" + "bin-version-check": "^5.0.0", + "download": "^8.0.0", + "os-filter-obj": "^2.0.0" }, "devDependencies": { - "ava": "*", + "ava": "^4.3.0", + "c8": "^7.11.3", "executable": "^4.1.1", - "nock": "^10.0.2", - "path-exists": "^3.0.0", - "rimraf": "^2.6.2", - "tempy": "^0.2.1", - "xo": "*" + "nock": "^13.2.6", + "path-exists": "^5.0.0", + "rimraf": "^3.0.2", + "tempy": "^2.0.0", + "xo": "^0.49.0" } } diff --git a/readme.md b/readme.md index ef3bbf0..909cf6c 100644 --- a/readme.md +++ b/readme.md @@ -13,7 +13,8 @@ npm install bin-wrapper ## Usage ```js -const BinWrapper = require('bin-wrapper'); +import path from 'node:path'; +import BinWrapper from 'bin-wrapper'; const base = 'https://github.com/imagemin/gifsicle-bin/raw/main/vendor'; const bin = new BinWrapper() diff --git a/test.js b/test.js index 5248cd7..042f208 100644 --- a/test.js +++ b/test.js @@ -1,21 +1,26 @@ -import fs from 'fs'; -import path from 'path'; +import fs from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import {promisify} from 'node:util'; +import {fileURLToPath} from 'node:url'; +import executable from 'executable'; import nock from 'nock'; -import pathExists from 'path-exists'; -import pify from 'pify'; +import {pathExists} from 'path-exists'; import rimraf from 'rimraf'; -import test from 'ava'; import tempy from 'tempy'; -import executable from 'executable'; -import Fn from '.'; +import test from 'ava'; +import BinWrapper from './index.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const rimrafP = pify(rimraf); +const rimrafP = promisify(rimraf); const fixture = path.join.bind(path, __dirname, 'fixtures'); test.beforeEach(() => { nock('http://foo.com') .get('/gifsicle.tar.gz') - .replyWithFile(200, fixture('gifsicle-' + process.platform + '.tar.gz')) + .replyWithFile(200, fixture(`gifsicle-${process.platform}.tar.gz`)) .get('/gifsicle-darwin.tar.gz') .replyWithFile(200, fixture('gifsicle-darwin.tar.gz')) .get('/gifsicle-win32.tar.gz') @@ -25,36 +30,36 @@ test.beforeEach(() => { }); test('expose a constructor', t => { - t.is(typeof Fn, 'function'); + t.is(typeof BinWrapper, 'function'); }); test('add a source', t => { - const bin = new Fn().src('http://foo.com/bar.tar.gz'); + const bin = new BinWrapper().src('http://foo.com/bar.tar.gz'); t.is(bin._src[0].url, 'http://foo.com/bar.tar.gz'); }); test('add a source to a specific os', t => { - const bin = new Fn().src('http://foo.com', process.platform); + const bin = new BinWrapper().src('http://foo.com', process.platform); t.is(bin._src[0].os, process.platform); }); test('set destination directory', t => { - const bin = new Fn().dest(path.join(__dirname, 'foo')); + const bin = new BinWrapper().dest(path.join(__dirname, 'foo')); t.is(bin._dest, path.join(__dirname, 'foo')); }); test('set which file to use as the binary', t => { - const bin = new Fn().use('foo'); + const bin = new BinWrapper().use('foo'); t.is(bin._use, 'foo'); }); test('set a version range to test against', t => { - const bin = new Fn().version('1.0.0'); + const bin = new BinWrapper().version('1.0.0'); t.is(bin._version, '1.0.0'); }); test('get the binary path', t => { - const bin = new Fn() + const bin = new BinWrapper() .dest('tmp') .use('foo'); @@ -62,7 +67,7 @@ test('get the binary path', t => { }); test('verify that a binary is working', async t => { - const bin = new Fn() + const bin = new BinWrapper() .src('http://foo.com/gifsicle.tar.gz') .dest(tempy.directory()) .use(process.platform === 'win32' ? 'gifsicle.exe' : 'gifsicle'); @@ -73,7 +78,7 @@ test('verify that a binary is working', async t => { }); test('meet the desired version', async t => { - const bin = new Fn() + const bin = new BinWrapper() .src('http://foo.com/gifsicle.tar.gz') .dest(tempy.directory()) .use(process.platform === 'win32' ? 'gifsicle.exe' : 'gifsicle') @@ -85,7 +90,7 @@ test('meet the desired version', async t => { }); test('download files even if they are not used', async t => { - const bin = new Fn({strip: 0, skipCheck: true}) + const bin = new BinWrapper({strip: 0, skipCheck: true}) .src('http://foo.com/gifsicle-darwin.tar.gz') .src('http://foo.com/gifsicle-win32.tar.gz') .src('http://foo.com/test.js') @@ -104,7 +109,7 @@ test('download files even if they are not used', async t => { }); test('skip running binary check', async t => { - const bin = new Fn({skipCheck: true}) + const bin = new BinWrapper({skipCheck: true}) .src('http://foo.com/gifsicle.tar.gz') .dest(tempy.directory()) .use(process.platform === 'win32' ? 'gifsicle.exe' : 'gifsicle'); @@ -115,15 +120,15 @@ test('skip running binary check', async t => { }); test('error if no binary is found and no source is provided', async t => { - const bin = new Fn() + const bin = new BinWrapper() .dest(tempy.directory()) .use(process.platform === 'win32' ? 'gifsicle.exe' : 'gifsicle'); - await t.throws(bin.run(), 'No binary found matching your system. It\'s probably not supported.'); + await t.throwsAsync(bin.run(), undefined, 'No binary found matching your system. It\'s probably not supported.'); }); test('downloaded files are set to be executable', async t => { - const bin = new Fn({strip: 0, skipCheck: true}) + const bin = new BinWrapper({strip: 0, skipCheck: true}) .src('http://foo.com/gifsicle-darwin.tar.gz') .src('http://foo.com/gifsicle-win32.tar.gz') .src('http://foo.com/test.js') @@ -134,7 +139,7 @@ test('downloaded files are set to be executable', async t => { const files = fs.readdirSync(bin.dest()); - files.forEach(fileName => { + for (const fileName of files) { t.true(executable.sync(path.join(bin.dest(), fileName))); - }); + } });