Skip to content

Commit

Permalink
fix: add workaround to expand directory when globbing
Browse files Browse the repository at this point in the history
  • Loading branch information
pvdlg committed Jul 19, 2018
1 parent 1f906b4 commit 0665441
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 36 deletions.
29 changes: 25 additions & 4 deletions lib/glob-assets.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,44 @@
const path = require('path');
const {basename} = require('path');
const {isPlainObject, castArray, uniqWith} = require('lodash');
const {isPlainObject, castArray, uniqWith, uniq} = require('lodash');
const dirGlob = require('dir-glob');
const globby = require('globby');
const debug = require('debug')('semantic-release:github');

const filesTransform = (files, cwd, transform) =>
files.map(file => `${file.startsWith('!') ? '!' : ''}${transform(cwd, file.startsWith('!') ? file.slice(1) : file)}`);

module.exports = async ({cwd}, assets) =>
uniqWith(
[]
.concat(
...(await Promise.all(
assets.map(async asset => {
// Wrap single glob definition in Array
const glob = castArray(isPlainObject(asset) ? asset.path : asset);
let glob = castArray(isPlainObject(asset) ? asset.path : asset);
// TODO Temporary workaround for https://github.com/kevva/dir-glob/issues/7 and https://github.com/mrmlnc/fast-glob/issues/47
glob = uniq([
...filesTransform(await dirGlob(filesTransform(glob, cwd, path.resolve)), cwd, path.relative),
...glob,
]);

// Skip solo negated pattern (avoid to include every non js file with `!**/*.js`)
if (glob.length <= 1 && glob[0].startsWith('!')) {
debug(
'skipping the negated glob %o as its alone in its group and would retrieve a large amount of files ',
'skipping the negated glob %o as its alone in its group and would retrieve a large amount of files',
glob[0]
);
return [];
}
const globbed = await globby(glob, {cwd, expandDirectories: true, gitignore: false, dot: true});

const globbed = await globby(glob, {
cwd,
expandDirectories: true,
gitignore: false,
dot: true,
onlyFiles: false,
});

if (isPlainObject(asset)) {
if (globbed.length > 1) {
// If asset is an Object with a glob the `path` property that resolve to multiple files,
Expand All @@ -34,10 +53,12 @@ module.exports = async ({cwd}, assets) =>
// - other properties of the original asset definition
return {...asset, path: globbed[0] || asset.path};
}

if (globbed.length > 0) {
// If asset is a String definition, output each files matched
return globbed;
}

// If asset is a String definition but no match is found, output the elements of the original glob (each one will be considered as a missing file)
return glob;
})
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"aggregate-error": "^1.0.0",
"bottleneck": "^2.0.1",
"debug": "^3.1.0",
"dir-glob": "^2.0.0",
"fs-extra": "^7.0.0",
"globby": "^8.0.0",
"http-proxy-agent": "^2.1.0",
Expand Down
108 changes: 76 additions & 32 deletions test/glob-assets.test.js
Original file line number Diff line number Diff line change
@@ -1,141 +1,185 @@
import path from 'path';
import test from 'ava';
import {copy, ensureDir} from 'fs-extra';
import {isPlainObject, sortBy} from 'lodash';
import tempy from 'tempy';
import globAssets from '../lib/glob-assets';

const cwd = 'test/fixtures/files';
const sortAssets = assets => sortBy(assets, asset => (isPlainObject(asset) ? asset.path : asset));

const fixtures = 'test/fixtures/files';

test('Retrieve file from single path', async t => {
const cwd = tempy.directory();
await copy(fixtures, cwd);
const globbedAssets = await globAssets({cwd}, ['upload.txt']);

t.deepEqual(globbedAssets, ['upload.txt']);
});

test('Retrieve multiple files from path', async t => {
const globbedAssets = (await globAssets({cwd}, ['upload.txt', 'upload_other.txt'])).sort();
const cwd = tempy.directory();
await copy(fixtures, cwd);
const globbedAssets = await globAssets({cwd}, ['upload.txt', 'upload_other.txt']);

t.deepEqual(globbedAssets, ['upload_other.txt', 'upload.txt'].sort());
t.deepEqual(sortAssets(globbedAssets), sortAssets(['upload_other.txt', 'upload.txt']));
});

test('Include missing files as defined, using Object definition', async t => {
const globbedAssets = (await globAssets({cwd}, ['upload.txt', {path: 'miss*.txt', label: 'Missing'}])).sort();
const cwd = tempy.directory();
await copy(fixtures, cwd);
const globbedAssets = await globAssets({cwd}, ['upload.txt', {path: 'miss*.txt', label: 'Missing'}]);

t.deepEqual(globbedAssets, ['upload.txt', {path: 'miss*.txt', label: 'Missing'}].sort());
t.deepEqual(sortAssets(globbedAssets), sortAssets(['upload.txt', {path: 'miss*.txt', label: 'Missing'}]));
});

test('Retrieve multiple files from Object', async t => {
const globbedAssets = (await globAssets({cwd}, [
const cwd = tempy.directory();
await copy(fixtures, cwd);
const globbedAssets = await globAssets({cwd}, [
{path: 'upload.txt', name: 'upload_name', label: 'Upload label'},
'upload_other.txt',
])).sort();
]);

t.deepEqual(
globbedAssets,
[{path: 'upload.txt', name: 'upload_name', label: 'Upload label'}, 'upload_other.txt'].sort()
sortAssets(globbedAssets),
sortAssets([{path: 'upload.txt', name: 'upload_name', label: 'Upload label'}, 'upload_other.txt'])
);
});

test('Retrieve multiple files without duplicates', async t => {
const globbedAssets = (await globAssets({cwd}, [
const cwd = tempy.directory();
await copy(fixtures, cwd);
const globbedAssets = await globAssets({cwd}, [
'upload_other.txt',
'upload.txt',
'upload_other.txt',
'upload.txt',
'upload.txt',
'upload_other.txt',
])).sort();
]);

t.deepEqual(globbedAssets, ['upload_other.txt', 'upload.txt'].sort());
t.deepEqual(sortAssets(globbedAssets), sortAssets(['upload_other.txt', 'upload.txt']));
});

test('Favor Object over String values when removing duplicates', async t => {
const globbedAssets = (await globAssets({cwd}, [
const cwd = tempy.directory();
await copy(fixtures, cwd);
const globbedAssets = await globAssets({cwd}, [
'upload_other.txt',
'upload.txt',
{path: 'upload.txt', name: 'upload_name'},
'upload.txt',
{path: 'upload_other.txt', name: 'upload_other_name'},
'upload.txt',
'upload_other.txt',
])).sort();
]);

t.deepEqual(
globbedAssets,
[{path: 'upload.txt', name: 'upload_name'}, {path: 'upload_other.txt', name: 'upload_other_name'}].sort()
sortAssets(globbedAssets),
sortAssets([{path: 'upload.txt', name: 'upload_name'}, {path: 'upload_other.txt', name: 'upload_other_name'}])
);
});

test('Retrieve file from single glob', async t => {
const cwd = tempy.directory();
await copy(fixtures, cwd);
const globbedAssets = await globAssets({cwd}, ['upload.*']);

t.deepEqual(globbedAssets, ['upload.txt']);
});

test('Retrieve multiple files from single glob', async t => {
const globbedAssets = (await globAssets({cwd}, ['*.txt'])).sort();
const cwd = tempy.directory();
await copy(fixtures, cwd);
const globbedAssets = await globAssets({cwd}, ['*.txt']);

t.deepEqual(globbedAssets, ['upload_other.txt', 'upload.txt'].sort());
t.deepEqual(sortAssets(globbedAssets), sortAssets(['upload_other.txt', 'upload.txt']));
});

test('Accept glob array with one value', async t => {
const globbedAssets = (await globAssets({cwd}, [['*load.txt'], ['*_other.txt']])).sort();
const cwd = tempy.directory();
await copy(fixtures, cwd);
const globbedAssets = await globAssets({cwd}, [['*load.txt'], ['*_other.txt']]);

t.deepEqual(globbedAssets, ['upload_other.txt', 'upload.txt'].sort());
t.deepEqual(sortAssets(globbedAssets), sortAssets(['upload_other.txt', 'upload.txt']));
});

test('Include globs that resolve to no files as defined', async t => {
const globbedAssets = (await globAssets({cwd}, [['upload.txt', '!upload.txt']])).sort();
const cwd = tempy.directory();
await copy(fixtures, cwd);
const globbedAssets = await globAssets({cwd}, [['upload.txt', '!upload.txt']]);

t.deepEqual(globbedAssets, ['!upload.txt', 'upload.txt'].sort());
t.deepEqual(sortAssets(globbedAssets), sortAssets(['!upload.txt', 'upload.txt']));
});

test('Accept glob array with one value for missing files', async t => {
const globbedAssets = (await globAssets({cwd}, [['*missing.txt'], ['*_other.txt']])).sort();
const cwd = tempy.directory();
await copy(fixtures, cwd);
const globbedAssets = await globAssets({cwd}, [['*missing.txt'], ['*_other.txt']]);

t.deepEqual(globbedAssets, ['upload_other.txt', '*missing.txt'].sort());
t.deepEqual(sortAssets(globbedAssets), sortAssets(['upload_other.txt', '*missing.txt']));
});

test('Replace name by filename for Object that match multiple files', async t => {
const globbedAssets = (await globAssets({cwd}, [{path: '*.txt', name: 'upload_name', label: 'Upload label'}])).sort();
const cwd = tempy.directory();
await copy(fixtures, cwd);
const globbedAssets = await globAssets({cwd}, [{path: '*.txt', name: 'upload_name', label: 'Upload label'}]);

t.deepEqual(
globbedAssets,
[
sortAssets(globbedAssets),
sortAssets([
{path: 'upload.txt', name: 'upload.txt', label: 'Upload label'},
{path: 'upload_other.txt', name: 'upload_other.txt', label: 'Upload label'},
].sort()
])
);
});

test('Include dotfiles', async t => {
const cwd = tempy.directory();
await copy(fixtures, cwd);
const globbedAssets = await globAssets({cwd}, ['.dot*']);

t.deepEqual(globbedAssets, ['.dotfile']);
});

test('Ingnore single negated glob', async t => {
const cwd = tempy.directory();
await copy(fixtures, cwd);
const globbedAssets = await globAssets({cwd}, ['!*.txt']);

t.deepEqual(globbedAssets, []);
});

test('Ingnore single negated glob in Object', async t => {
const cwd = tempy.directory();
await copy(fixtures, cwd);
const globbedAssets = await globAssets({cwd}, [{path: '!*.txt'}]);

t.deepEqual(globbedAssets, []);
});

test('Accept negated globs', async t => {
const cwd = tempy.directory();
await copy(fixtures, cwd);
const globbedAssets = await globAssets({cwd}, [['*.txt', '!**/*_other.txt']]);

t.deepEqual(globbedAssets, ['upload.txt']);
});

test('Expand directories', async t => {
const globbedAssets = (await globAssets({cwd}, [['.']])).sort();
const cwd = tempy.directory();
await copy(fixtures, path.resolve(cwd, 'dir'));
const globbedAssets = await globAssets({cwd}, [['dir']]);

t.deepEqual(globbedAssets, ['upload_other.txt', 'upload.txt', '.dotfile'].sort());
t.deepEqual(sortAssets(globbedAssets), sortAssets(['dir', 'dir/upload_other.txt', 'dir/upload.txt', 'dir/.dotfile']));
});

test('Include empty directory as defined', async t => {
const globbedAssets = await globAssets({cwd}, [['test/empty']]);
const cwd = tempy.directory();
await copy(fixtures, cwd);
await ensureDir(path.resolve(cwd, 'empty'));
const globbedAssets = await globAssets({cwd}, [['empty']]);

t.deepEqual(globbedAssets, ['test/empty']);
t.deepEqual(globbedAssets, ['empty']);
});

0 comments on commit 0665441

Please sign in to comment.