개발/Today I Learned

husky와 commitlint를 사용하여 commit 규칙을 지키며 협업하기

devmomori 2022. 3. 31. 18:40

작업을 하다 보면 commit 규칙이 있음에도 불구하고 의도치 않게 실수하여 commit을 되돌리거나 모르는 채로 push까지 하게 될 수 있다. 페어 프로그래밍을 진행하면서 페어와 commit이 다를 수 있다는 것을 인지하게 되었다.

 

어떻게 하면 서로가 규칙을 지키면서, 또 실수를 방지하며 commit 메시지를 작성할 수 있을지 고민하게 되었다.

 

알아보니 githooks 혹은 husky 그리고 commitlint를 사용하여 이러한 부분들을 해결할 수 있다는 것을 알게 되었고 레포지토리를 만들어 실습해보았다.

 

실습 레포는 하단 링크에서 볼 수 있다.

 

GitHub - somedaycode/husky_commitlint_test: test git commit and push with lint

test git commit and push with lint. Contribute to somedaycode/husky_commitlint_test development by creating an account on GitHub.

github.com


husky와 commitlint를 사용한 방법

설치

필요한 패키지를 받고, commitlint.config.js 에 컨벤션을 붙여준다.

 

husky install 을 통해서 .husky folder 내부에 commit-msg 파일을 생성해준다.

 

commit-msg를 통해 commit을 할 때마다 lint를 확인해준다.

yarn add -D husky @commitlint/config-conventional @commitlint/cli

echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js

yarn husky install or npx husky install

yarn husky add .husky/commit-msg "yarn commitlint --edit $1"

 

Default

아래의 코드는 따로 설정해주는 것이 아니라  @commitlint/config-conventional 내부 코드를 가져온 것이다.

 

위에서 설정한 extends: [...] 를 통해서 기본 값이 된다.

// @commitlint/config-conventional 기본 설정

module.exports = {
  parserPreset: 'conventional-changelog-conventionalcommits',
  rules: {
    'body-leading-blank': [
      1,
      'always'
    ],
    'body-max-line-length': [
      2,
      'always',
      100
    ],
    'footer-leading-blank': [
      1,
      'always'
    ],
    'footer-max-line-length': [
      2,
      'always',
      100
    ],
    'header-max-length': [
      2,
      'always',
      100
    ],
    'subject-case': [
      2,
      'never',
      [
        'sentence-case',
        'start-case',
        'pascal-case',
        'upper-case'
      ]
    ],
    'subject-empty': [
      2,
      'never'
    ],
    'subject-full-stop': [
      2,
      'never',
      '.'
    ],
    'type-case': [
      2,
      'always',
      'lower-case'
    ],
    'type-empty': [
      2,
      'never'
    ],
    'type-enum': [
      2,
      'always',
      [
        'build',
        'chore',
        'ci',
        'docs',
        'feat',
        'fix',
        'perf',
        'refactor',
        'revert',
        'style',
        'test'
      ]
    ]
  }
}

Custom Rule

기본적으로 제공되는 규칙 뿐만 아니라 원하는 규칙들을 추가로 넣어줄 수 있다.

// custom rules 추가

module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'develop-rule': [2, 'always'],
  },
  plugins: [
    {
      rules: {
        'develop-rule': ({subject}) => {
          const commitFolders = ['[frontend]', '[backend]', '[domain]', '[root]'];
          return [
            commitFolders.some((folder) => subject?.startsWith(folder) !== subject?.endsWith(folder)),
            `\n${commitFolders.map(folder => `${folder}\n`).join('')}
위 네 가지 중 한 가지는 반드시 콜론(:) 뒤에 포함되어야 합니다.
[name] 뒤에 메시지 입력은 필수입니다.

ex) feat: [frontend] 마우스 더블클릭 후 스타일 변경`
          ]
        },
      },
    }
  ]
};

 

TEST

실패와 성공 케이스들을 여러가지 테스트 해보았는데 그 중 몇가지를 가져왔다.

// fail
git commit -m 'docs: README.md'

or

git commit -m 'docs:[frontend]

//success
git commit -m 'docs: [frontend] README.md'

 


 

마무리

프로그램의 도움 없이 규칙을 정확하게 지켜서 commit을 할 수도 있지만, human error라는 것이 있으니 이러한 도구들의 도움을 받는다면 좀 더 수월하게 (commit 실수에 관대해지며) 협업을 원할하게 나아갈 수 있지 않을까?