Gulp e hooks de commits (gilp)

Este post faz parte da série sobre ferramentas para garantir a qualidade do código.
Ao criar um fluxo de validação para os arquivos preparados para um commit, não há muitas opções e geralmente se termina com um enorme script de Bash cheio de funções para cada linter, regra ou padrão que se queira automatizar.
Este post apresenta o gilp, um plugin do gulp que cuida da instalação dos hooks pre-commit, pre-push e commit-msg e da execução de tarefas do gulp.
Fluxo de validação
Assim como o gulp oferece gulp.src, o gilp oferece gilp.srcFromStaged, uma função semelhante que exclui os arquivos não preparados para o commit e retorna um fluxo de objetos File do vinyl. O gilp também oferece gilp.srcFromCommit, que recebe o hash de uma revisão.
Este exemplo inclui gulp-eslint para validar JavaScript.
gilp.hook('pre-commit', ['check-eslint'], () =>
gilp.srcFromStaged(['**/*'.js])
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError())
gilp.hook se comporta de forma semelhante a gulp.task, mas é registrado em ./git/hooks e envolve a tarefa original de gulp.task.
Vamos ver agora um exemplo mínimo funcional.
Exemplo
Normalmente começamos separando nossas verificações em funções diferentes.
const filter = require('gulp-filter');
const combiner = require('stream-combiner2').obj;
const print = require('gulp-print');
const flake8 = require('gulp-flake8');
const gulpIsort = require('gulp-isort');
const checkGrep = require('gulp-check-grep');
function py() {
const src = filter([
'**/*.py',
], {restore: true});
return combiner(
src,
print(),
flake8('.flake8'),
flake8.failOnError(),
gulpIsort(),
gulpIsort.failOnError(),
checkGrep(/print\+$/gm, {pass: (line, n, f) => line.endswith('# noqa')}),
checkGrep.failOnError(),
src.restore
);
}
Aqui usamos stream-combiner2 para que nossa função py se comporte como um único fluxo, e gulp-filter para selecionar apenas os arquivos Python.
const filter = require('gulp-filter');
const combiner = require('stream-combiner2').obj;
const print = require('gulp-print');
const lintFilepath = require('gulp-lint-filepath');
function html() {
const src = filter(['**/*.html'], {restore: true});
return combiner(
src,
print(),
lintFilepath({'file-name': [/(^|\/)[a-z0-9_]+\.html$/]}),
lintFilepath.reporter(),
src.restore
);
}
Isso faz mais ou menos o mesmo, mas usa um validador de nomes de arquivo do gulp para arquivos HTML.
const gilp = require('gilp');
gilp.hook('pre-commit', () =>
gilp.srcFromStaged(['**/*'])
.pipe(py())
.pipe(html())
);
Aqui está definido o hook do gilp: executar gulp gilp-install colocará essas tarefas no arquivo de hooks pre-commit.