DEV Community

Eduardo Rabelo
Eduardo Rabelo

Posted on

Aplicando Padrões de Código com Pré-Commit Hook usando Husky

Neste artigo, aprenderemos como configurar o Husky para evitar git commits ruins e impor padrões de código em seu projeto.

Introdução

Na maioria dos projetos em que já trabalhei de forma colaborativa, alguém assume o papel de campeão de limpeza de código. Geralmente é o líder da equipe e, muitas vezes, sua função envolve revisar os PRs e garantir que o amor e o cuidado sejam colocados na qualidade do código.

A qualidade inclui as convenções e padrões de código escolhidas, além da formatação do código.

Hoje, é uma boa prática em projetos JavaScript utilizar ESLint para definir as convenções de código do projeto. Por exemplo, como sua equipe se sente em relação ao uso de for loops? E o ponto-e-vírgula - são obrigatórios? Etc.

Essas são convenções.

A outra peça do quebra-cabeça é a formatação. Essa é a aparência visual do código. Quando há mais de um desenvolvedor trabalhando em um projeto, garantir que o código pareça consistente é algo a ser abordado.

Prettier é a ferramenta correta para isso.

No artigo anterior, aprendemos como combinar ESLint e Prettier, mas não aprendemos como realmente aplicar as convenções e a formatação em um projeto da vida real com vários desenvolvedores.

Neste artigo, aprenderemos como usar o Husky para fazer isso em um projeto baseado em Git.

Husky

Husky é um pacote npm que "torna os hooks Git fáceis".

Quando você inicializa o Git (a ferramenta de controle de versão com a qual você provavelmente está familiarizado) em um projeto, ele vem automaticamente com um recurso chamado hooks.

Se você for até a raiz de um projeto inicializado com Git e digitar:

ls .git/hooks
Enter fullscreen mode Exit fullscreen mode

Você verá uma lista de ganchos de exemplo, como pre-push, pre-rebase, pre-commit e assim por diante. Esta é uma maneira de escrevermos algum código de plugin para executar alguma lógica antes de realizar a ação do Git.

Se quisermos garantir que seu código foi devidamente lintado e formatado, antes de alguém criar um commit usando o comando git commit, poderíamos escrever um hook Git de pre-commit.

Escrever isso manualmente provavelmente não seria divertido. Também seria um desafio distribuir e garantir que os hooks fossem instalados nas máquinas de outros desenvolvedores.

Esses são alguns dos desafios que o Husky pretende resolver.

Com o Husky, podemos garantir que, para um novo desenvolvedor trabalhando em nossa base de código (usando pelo menos o Node versão 10):

  • Hooks são criados localmente
  • Hooks são executados quando o comando Git é chamado
  • Aplicar uma regra que define como alguém pode contribuir para o projeto

Vamos configurá-lo.

Instalando Husky

Para instalar o Husky, execute:

npm install husky --save-dev
Enter fullscreen mode Exit fullscreen mode

Configurando Husky

Para configurar o Husky, na raiz do nosso projeto no package.json, adicione a seguinte chave husky:

{
  "husky": {
    "hooks": {
      "pre-commit": "", // seu comando vai aqui
      "pre-push": "", // seu comando vai aqui
      "...": "..."
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Quando executamos o comando git commit ou git push, o respectivo hook executará o script que fornecemos em nosso package.json.

Fluxo de trabalho de exemplo

Seguindo os exemplos dos artigos anteriores, se configurarmos o ESLint e Prettier, sugiro utilizar dois scripts:


{
  "scripts": {
    "prettier-format": "prettier --config .prettierrc 'src/**/*.ts' --write",
    "lint": "eslint . --ext .ts",
    ...
  },
  "husky": {
    "hooks": {
      "pre-commit": "npm run prettier-format && npm run lint"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Inclua esses scripts no objeto scripts em seu package.json. E execute prettier-format e depois lint com um hook pre-commit.

Isso garantirá que você não possa completar um commit sem que seu código seja formatado de acordo com as convenções do seu time.

Exemplo - Bloqueando um commit

Eu gosto de usar o pacote no-loops como exemplo. Esta convenção não permite aos desenvolvedores usar for loops, ao invés disso, sugere que usamos funções de utilidade do Array como forEach, map e afins.

Adicionando o plug-in e sua regra ao .eslintrc:

{
  "root": true,
  "parser": "@typescript-eslint/parser",
  "plugins": [
    "@typescript-eslint",
    "no-loops",
    "prettier"
  ],
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier"
  ],
  "rules": {
    "no-loops/no-loops": 2, // 2 singifica "retornar um errro"
    "no-console": 1,
    "prettier/prettier": 2
  }
}
Enter fullscreen mode Exit fullscreen mode

E vamos colocar um for loop no código-fonte:

console.log('Hello world!');

for (let i = 0; i < 12; i++) {
  console.log(i);
}
Enter fullscreen mode Exit fullscreen mode

E ao tentar commitar, veremos um código de saída diferente de zero, o que, como sabemos, significa que ocorreu um erro:

simple-typescript-starter git:(prettier) ✗ git commit -m "Test commit"
husky > pre-commit (node v10.10.0)

> typescript-starter@1.0.0 prettier-format simple-typescript-starter
> prettier --config .prettierrc 'src/**/*.ts' --write

src/index.ts 191ms

> typescript-starter@1.0.0 lint /simple-typescript-starter
> eslint . --ext .ts


/simple-typescript-starter/src/index.ts
  1:1  warning  Unexpected console statement  no-console
  3:1  error    loops are not allowed         no-loops/no-loops
  4:3  warning  Unexpected console statement  no-console

✖ 3 problems (1 error, 2 warnings)
Enter fullscreen mode Exit fullscreen mode

E aí está!

Outras considerações

Se você perceber que o lint está demorando muito, verifique este pacote, lint-staged. Ele executa o linter, mas apenas nos arquivos que estão em git stage (arquivos que você está pronto para commitar). Isso me foi sugerido por @glambertmtl. Obrigado!

Créditos

Top comments (0)