Skip to content
This repository has been archived by the owner on Dec 18, 2021. It is now read-only.

Commit

Permalink
feat(husky): reported a next-step when using v4 config with v5
Browse files Browse the repository at this point in the history
to prepare to automatically upgrade the config
  • Loading branch information
travi committed Dec 17, 2020
1 parent c2c35d4 commit a4a690f
Show file tree
Hide file tree
Showing 13 changed files with 230 additions and 17 deletions.
56 changes: 47 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
"@babel/register": "7.12.10",
"@form8ion/babel-preset": "1.6.41",
"@form8ion/commitlint-config": "1.0.14",
"@form8ion/core": "1.3.1",
"@form8ion/eslint-config": "1.7.2",
"@form8ion/eslint-config-cucumber": "1.4.0",
"@form8ion/eslint-config-mocha": "1.2.9",
Expand All @@ -64,6 +63,7 @@
"husky": "5.0.6",
"js-yaml": "3.14.1",
"lockfile-lint": "4.3.7",
"make-dir": "^3.1.0",
"mocha": "8.2.1",
"mock-fs": "4.13.0",
"npm-run-all": "4.1.5",
Expand All @@ -79,7 +79,11 @@
"testdouble": "3.16.1"
},
"dependencies": {
"@form8ion/core": "^1.3.1",
"@form8ion/javascript-core": "2.7.1",
"@travi/cli-messages": "^1.0.4"
"@travi/cli-messages": "^1.0.4",
"deepmerge": "^4.2.2",
"execa": "^5.0.0",
"semver": "^7.3.4"
}
}
69 changes: 69 additions & 0 deletions src/husky-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import * as core from '@form8ion/core';
import {assert} from 'chai';
import sinon from 'sinon';
import any from '@travi/any';
import * as execa from '../thirdparty-wrappers/execa';
import liftHusky from './husky';

suite('husky', () => {
let sandbox;
const projectRoot = any.string();

setup(() => {
sandbox = sinon.createSandbox();

sandbox.stub(core, 'fileExists');
sandbox.stub(execa, 'default');
});

teardown(() => sandbox.restore());

test('that a next-step is listed when v5 is installed, but config is still for v4', async () => {
core.fileExists.withArgs(`${projectRoot}/.huskyrc.json`).resolves(true);
execa.default
.withArgs('npm', ['ls', 'husky', '--json'])
.resolves(JSON.stringify({dependencies: {husky: {version: '5.0.0'}}}));

assert.deepEqual(
await liftHusky({projectRoot}),
{nextSteps: [{summary: 'Husky configuration is outdated for the installed Husky version'}]}
);
});

test('that a next-step is listed when greater than v5 is installed, but config is still for v4', async () => {
core.fileExists.withArgs(`${projectRoot}/.huskyrc.json`).resolves(true);
execa.default
.withArgs('npm', ['ls', 'husky', '--json'])
.resolves(JSON.stringify({dependencies: {husky: {version: '5.0.1'}}}));

assert.deepEqual(
await liftHusky({projectRoot}),
{nextSteps: [{summary: 'Husky configuration is outdated for the installed Husky version'}]}
);
});

test('that no next-step is listed when v4 is installed', async () => {
core.fileExists.withArgs(`${projectRoot}/.huskyrc.json`).resolves(true);
execa.default
.withArgs('npm', ['ls', 'husky', '--json'])
.resolves(JSON.stringify({dependencies: {husky: {version: '4.5.6'}}}));

assert.deepEqual(await liftHusky({projectRoot}), {});
});

test('that no next-step is listed when v5 is installed and v5 config exists', async () => {
execa.default
.withArgs('npm', ['ls', 'husky', '--json'])
.resolves(JSON.stringify({dependencies: {husky: {version: '5.6.7'}}}));
core.fileExists.resolves(false);

assert.deepEqual(await liftHusky({projectRoot}), {});
});

test('that not having husky installed does not result in an error', async () => {
execa.default.withArgs('npm', ['ls', 'husky', '--json']).resolves(JSON.stringify({}));
core.fileExists.resolves(any.boolean());

await liftHusky({projectRoot});
});
});
18 changes: 18 additions & 0 deletions src/husky.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import semver from 'semver';
import {fileExists} from '@form8ion/core';
import execa from '../thirdparty-wrappers/execa';

export default async function ({projectRoot}) {
const [huskyVersionDetails, huskyV4ConfigExists] = await Promise.all([
await execa('npm', ['ls', 'husky', '--json']),
await fileExists(`${projectRoot}/.huskyrc.json`)
]);

const {dependencies} = JSON.parse(huskyVersionDetails);

if (dependencies && semver.gte(dependencies.husky.version, '5.0.0') && huskyV4ConfigExists) {
return {nextSteps: [{summary: 'Husky configuration is outdated for the installed Husky version'}]};
}

return {};
}
12 changes: 9 additions & 3 deletions src/lift-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import sinon from 'sinon';
import any from '@travi/any';
import {assert} from 'chai';
import * as packageLifter from './package';
import * as huskyLifter from './husky';
import * as eslintLifter from './eslint/lift';
import lift from './lift';

Expand All @@ -14,12 +15,17 @@ suite('lift', () => {
const dependencies = any.listOf(any.word);
const devDependencies = any.listOf(any.word);
const results = {...any.simpleObject(), scripts, tags, eslintConfigs, dependencies, devDependencies};
const huskyNextSteps = any.listOf(any.simpleObject);
const huskyLiftResults = {nextSteps: huskyNextSteps};

setup(() => {
sandbox = sinon.createSandbox();

sandbox.stub(packageLifter, 'default');
sandbox.stub(eslintLifter, 'default');
sandbox.stub(huskyLifter, 'default');

huskyLifter.default.withArgs({projectRoot}).resolves(huskyLiftResults);
});

teardown(() => sandbox.restore());
Expand All @@ -37,7 +43,7 @@ suite('lift', () => {

const liftResults = await lift({projectRoot, results, configs: {eslint: {scope}}});

assert.deepEqual(liftResults, {nextSteps: eslintNextSteps});
assert.deepEqual(liftResults, {nextSteps: [...eslintNextSteps, ...huskyNextSteps]});
assert.calledWith(
packageLifter.default,
{projectRoot, scripts, tags, dependencies, devDependencies, eslintDevDependencies}
Expand All @@ -47,12 +53,12 @@ suite('lift', () => {
test('that eslint-configs are not processed if configs are not provided', async () => {
const liftResults = await lift({projectRoot, results});

assert.deepEqual(liftResults, {});
assert.deepEqual(liftResults, {nextSteps: huskyNextSteps});
});

test('that eslint-configs are not processed if config for eslint is not provided', async () => {
const liftResults = await lift({projectRoot, results, configs: any.simpleObject()});

assert.deepEqual(liftResults, {});
assert.deepEqual(liftResults, {nextSteps: huskyNextSteps});
});
});
8 changes: 6 additions & 2 deletions src/lift.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import {info, warn} from '@travi/cli-messages';
import deepmerge from 'deepmerge';
import liftPackage from './package';
import liftEslint from './eslint';
import liftHusky from './husky';

function configIsProvidedForEslint(configs) {
return configs && configs.eslint;
Expand All @@ -13,6 +15,8 @@ export default async function ({
}) {
info('Lifting JavaScript-specific details');

const huskyResults = await liftHusky({projectRoot});

if (configIsProvidedForEslint(configs)) {
const {
nextSteps,
Expand All @@ -21,12 +25,12 @@ export default async function ({

await liftPackage({projectRoot, scripts, tags, dependencies, devDependencies, eslintDevDependencies});

return {nextSteps};
return deepmerge({nextSteps}, huskyResults);
}

if (eslintConfigs) warn('Config for ESLint not provided. Skipping ESLint configuration');

await liftPackage({projectRoot, scripts, tags, dependencies, devDependencies});

return {};
return huskyResults;
}
2 changes: 2 additions & 0 deletions test/integration/features/eslint-configs.feature
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ Feature: ESLint Configs

Scenario: No existing config
Given no existing eslint config file is present
And husky is not installed
When the scaffolder results are processed
Then no eslint config file exists

Scenario: existing yaml config
Given an existing eslint config file is present
And husky is not installed
When the scaffolder results are processed
Then the yaml eslint config file contains the expected config
19 changes: 19 additions & 0 deletions test/integration/features/husky.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Feature: Husky

Scenario: Husky v5 installed, v4 config
Given husky v5 is installed
And husky config is in v4 format
When the scaffolder results are processed
Then the next-steps include a warning about the husky config

Scenario: Husky v5 installed, v5 config
Given husky v5 is installed
And husky config is in v5 format
When the scaffolder results are processed
Then the next-steps do not include a warning about the husky config

Scenario: Husky v4 installed, v4 config
Given husky v4 is installed
And husky config is in v4 format
When the scaffolder results are processed
Then the next-steps do not include a warning about the husky config
2 changes: 2 additions & 0 deletions test/integration/features/package-properties.feature
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ Feature: Package Properties
Scenario: Tags results when no existing keywords
Given there are no existing keywords
And tags are provided in the results
And husky is not installed
When the scaffolder results are processed
Then keywords from the results exist

Scenario: Tags results when some keywords exist
Given there are existing keywords
And tags are provided in the results
And husky is not installed
When the scaffolder results are processed
Then the existing keywords still exist
And keywords from the results exist
3 changes: 3 additions & 0 deletions test/integration/features/scripts.feature
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ Feature: Scripts

Scenario: No Additional Scripts from Results
Given no additional scripts are included in the results
And husky is not installed
When the scaffolder results are processed
Then the existing scripts still exist
And no extra scripts were added

Scenario: Additional Scripts Are Present in Results
Given additional scripts are included in the results
And husky is not installed
When the scaffolder results are processed
Then the existing scripts still exist
And the additional scripts exist

Scenario: Duplicate Scripts Are Present in Results
Given additional scripts that duplicate existing scripts are included in the results
And husky is not installed
When the scaffolder results are processed
Then the additional scripts exist
Loading

0 comments on commit a4a690f

Please sign in to comment.