Skip to content

Commit

Permalink
Add command to test a local bluprint from disk
Browse files Browse the repository at this point in the history
  • Loading branch information
jarib committed Jul 14, 2022
1 parent a026dc7 commit 0d97bc0
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 3 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,6 @@ tmp/
temp/

# End of https://www.gitignore.io/api/node,macos,linux
n

# Editor
.vscode
11 changes: 10 additions & 1 deletion lib/cli.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { add, clone, newBluprint, remove, start, token } from 'bluprint';
import { add, clone, newBluprint, remove, start, token, test } from 'bluprint';
import { name, version } from '../package.json';

import chalk from 'chalk';
Expand Down Expand Up @@ -66,4 +66,13 @@ yargs // eslint-disable-line no-unused-expressions
}, async function({ accessToken }) {
await token(accessToken);
})
.command('test [directory]', 'Test the bluprint in the given directory', (yargs) => {
yargs
.positional('directory', {
describe: 'Local path to a bluprint',
type: 'string',
});
}, async function({ directory }) {
await test(directory);
})
.argv;
4 changes: 3 additions & 1 deletion lib/commands/start/fetchBluprint/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ export default (resolve, reject, filterGlobs, mergeJson) => {
if (entry.type === 'Directory') {
fs.mkdirSync(entryPath, { recursive: true });
entry.resume();
} else if (entry.type === 'File') {
} else if (['File', 'SymbolicLink'].includes(entry.type)) {
archive[entryPath] = [];
entry.on('data', c => archive[entryPath].push(c));
} else {
throw new Error(`unable to handle entry of type ${entry.type}`);
}
},
})
Expand Down
93 changes: 93 additions & 0 deletions lib/commands/test/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import fs from 'fs';
import path from 'path';
import tar from 'tar';
import os from 'os';

import handleActions from '../../actions';
import getLogger from '../../utils/getLogger';
import choosePart from '../start/choosePart';
import getParser from '../start/fetchBluprint/parser';
import minimatch from 'minimatch';

const logger = getLogger();

// best effort attempt at reproducing .gitignore behaviour
const createIgnoreFilter = config => {
const globs = fs.readFileSync(config, 'utf-8').split('\n').filter(line => !line.trim().startsWith('#'));
return file => !globs.some(glob => file.startsWith(glob) || minimatch(file, glob));
};

const getFiles = dir => {
const basename = path.basename(dir);
const files = fs.readdirSync(dir);
const result = [];

let filterFn = () => true;

for (const file of files) {
const fullPath = path.join(dir, file);

if (file === '.gitignore') {
filterFn = createIgnoreFilter(fullPath);
}

if (fs.statSync(fullPath).isDirectory()) {
getFiles(fullPath).forEach(f => result.push(f));
} else {
result.push(file);
}
}

return result.filter(e => filterFn(e) && !e.match(/^\.git(\/|$)/)).map(e => [basename, path.sep, e].join(''));
};

const buildTarball = async(directory) => {
const tarball = path.join(os.tmpdir(), 'tmp-bluprint.tar');
const files = getFiles(directory);

await tar.create({
gzip: false,
file: tarball,
cwd: path.dirname(directory),
strict: true,
}, files);

return tarball;
};

const fetchBluprint = async(tarballPath, filterGlobs, mergeJson) => {
return new Promise((resolve, reject) => {
const rs = fs.createReadStream(tarballPath);
const parser = getParser(resolve, reject, filterGlobs, mergeJson);

rs.pipe(parser)
.on('error', (e) => {
logger.error(`Tarball parsing error.`);
reject(e);
});
});
};

const defaultInject = {
method: null,
category: null,
bluprint: null,
partConfirm: null,
partChoice: null,
};

export default async(directory, inject = defaultInject) => {
const bluprintrc = JSON.parse(fs.readFileSync(path.join(directory, '.bluprintrc')));

const { parts, mergeJson } = bluprintrc;
const { part, globs: filterGlobs } = await choosePart(parts, inject);

const tarball = await buildTarball(directory);

try {
await fetchBluprint(tarball, filterGlobs, mergeJson);
await handleActions(bluprintrc.actions, part);
} finally {
fs.rmSync(tarball);
}
};
1 change: 1 addition & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export { default as remove } from './commands/remove';
export { default as start } from './commands/start';
export { default as clone } from './commands/clone';
export { default as token } from './commands/token';
export { default as test } from './commands/test';

export { default as handleActions } from './actions';

Expand Down
73 changes: 73 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
const expect = require('expect.js');
const path = require('path');
const { test } = require('../dist');
const os = require('os');
const fs = require('fs');

const resolvePath = (filePath) => path.join(process.cwd(), filePath);

const createTestBluprint = function() {
const tempdir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-bluprint'));

fs.writeFileSync(path.join(tempdir, '.bluprintrc'), JSON.stringify({
bluprint: '^0.0.1',
name: 'My test bluprint',
category: 'testing',
actions: [
{
action: 'render',
engine: 'mustache',
context: { foo: 'bar' },
files: [
'test-command-1.txt',
'subdir/test-command-2.txt',
],
},
],
}));

fs.mkdirSync(path.join(tempdir, 'subdir'));
fs.writeFileSync(path.join(tempdir, 'test-command-1.txt'), 'foo = {{ foo }}');
fs.writeFileSync(path.join(tempdir, 'subdir', 'test-command-2.txt'), 'foo = {{ foo }}');
fs.writeFileSync(path.join(tempdir, 'subdir', 'ignored.txt'), 'ignore me');
fs.writeFileSync(path.join(tempdir, 'subdir', '.gitignore'), '# this should be ignored\nignored.*');

return tempdir;
};

describe('Test command: test', function() {
this.timeout(10000);

let testBluprint;
let cleanupFiles;

beforeEach(async function() {
testBluprint = createTestBluprint();

cleanupFiles = [
testBluprint,
resolvePath('test-command-1.txt'),
resolvePath('subdir/test-command-2.txt'),
resolvePath('subdir/ignored.txt'),
resolvePath('subdir/.gitignore'),
resolvePath('subdir'),
];
});

afterEach(function() {
cleanupFiles.forEach(f => fs.rmSync(f, { recursive: true, force: true }));
});

it('Creates a new project from a bluprint directory', async function() {
await test(testBluprint);

expect(fs.readFileSync('test-command-1.txt', 'utf8')).to.be('foo = bar');
expect(fs.readFileSync('subdir/test-command-2.txt', 'utf8')).to.be('foo = bar');
});

it('Ignores files from .gitignore', async function() {
await test(testBluprint);

expect(fs.existsSync('ignored.txt')).to.be(false);
});
});

0 comments on commit 0d97bc0

Please sign in to comment.