[개발 환경] commitlint + prompt + gitmoji 로 일관적인 커밋 메시지 만들기

Chad Lee·2024년 5월 16일
0

개발 환경

목록 보기
2/2

개요

  팀에 모노레포가 적용 되었고 이에 개별 저장소에 관리되었던 프로젝트들과 신규 프로젝트 들이 하나의 레포지토리에 관리 되게 되었다. 이에 모두가 하나의 저장소에서 작업을 하고 커밋을 해야 하는데 일관적인 포맷의 커밋 메시지를 작성이 필요하게 되었다.

목표

  개발자 모두가 하나의 저장소에서 일어나는 프로젝트의 업데이트 상황과 히스토리를 동일한 컨벤션을 가지고 파악 할 수 있는 것을 큰 목표로 삼고 이를 이루기 위한 세부 목표를 잡아 보자.

  1. 커밋 메시지 포맷 정의
  2. 정의한 포맷에 맞게 작성 했는지 커밋 전에 확인
  3. 개발자가 포맷에 맞게 메시지를 작성하는데 실수하기 어려운 환경 제공
  4. 보기 편한 메시지

실행

먼저 커밋 메시지의 포맷은 Convaltional Commits 에서 정의 해 놓은 기본 포맷을 사용한다. 아래의 구조를 가지고 있다.

<타입>[적용 범위(선택 사항)]: <설명>

[본문(선택 사항)]

[꼬리말(선택 사항)]

이제 위의 구조와 다른 커밋이 들어 오면 커밋이 완료 되지 않고 어느 부분이 잘 못 되었는지 에러를 밷어 내면 된다.

이를 만족 하기 위해서는 커밋 메시지를 파싱하여 정의된 포맷과 일치하는지 확인 하는 도구가 필요한데 가장 많이 쓰는 도구로 commitlint 라는 도구가 있다. 이름만 봐도 명확하게 하는 일이 뭔지 알 수 있다.

1, 2 번의 목표는 commitlint를 이용하면 쉽게 해결 된다.
커밋 메시지를 작성하면 husky의 hook을 이용해 커밋 전에 포맷 맞게 작성 되었는지 확인 해서 0(성공) 또는 1(실패)을 반환 한다. 물론 포맷에 맞지 않는 부분도 알려 준다.

좀 더 알아 보자면 commitlint는 linter의 역할을 한다. 물론 commitlint.config.js 파일의 설정을 기준으로 linting 한다. 직접 rule등을 설정 할 수도 있지만, 이때 shared config를 사용하면 별다른 설정 없이 쉽게 사용 가능하다. commitlint 는 기본 적으로 @commitlint/config-conventional 이라는 shared config 를 제공하고 아래와 같이 쉽게 참조 하여 사용한다.

extends: ['@commitlint/config-conventional']

여기서 shared config란 미리 정의된 commitlint의 config 라고 생각하면 편하다. 그렇기 때문에 개별 프로젝트들에서 사용하는 shared config 들이 존재 한다.

예를 들어 atom이나, angular, gitmoji 등이 있다. 또 개인들이 사용하는 config 들도 존재 하니 사용하거나 나만의 shared config를 만들어 배포 해보는것도 좋을것 같다.

3번 목표를 완료 하기 위해서는 prompt 기능을 사용할 수 있다. 공홈의 가이드 처럼 사용해 보았는데 4번 목표 완료를 위해 imoji를 위해 사용하기 위한 gitmoji extends와 서로 맞지 않는다. 같이 쓰기 위해서는 parser를 별도로 만들어야 할것 같은데 이미 누가 해놓았다.
cz-customizable을 이용해 설정 하면 되는데 나의 config는 아래와 같다.

// cz-config.cjs
module.exports = {
  types: [
    {
      value: '✨ feat',
      name: '✨ feat:\tAdding a new feature'
    },
    { value: '🐛 fix',
      name: '🐛 fix:\tFixing a bug'
    },
    {
      value: '📝 docs',
      name: '📝 docs:\tAdd or update documentation'
    },
    {
      value: '💄 style',
      name: '💄 style:\tAdd or update styles, ui or ux',
    },
    {
      value: '♻️ refactor',
      name: '♻️ refactor:\tCode change that neither fixes a bug nor adds a feature',
    },
    {
      value: '⚡️ perf',
      name: '⚡️ perf:\tCode change that improves performance',
    },
    {
      value: '✅ test',
      name: '✅ test:\tAdding tests cases',
    },
    {
      value: '🚚 chore',
      name: '🚚 chore:\tChanges to the build process or auxiliary tools\n\t\tand libraries such as documentation generation',
    },
    {
      value: '⏪️ revert',
      name: '⏪️ revert:\tRevert to a commit' },
    { 
      value: '🚧 wip',
      name: '🚧 wip:\tWork in progress' },
    {
      value: '👷 build',
      name: '👷 build:\tAdd or update regards to build process',
    },
    {
      value: '💚 ci',
      name: '💚 ci:\tAdd or update regards to build process',
    },
  ],

  messages: {
    type: "Select the type of change that you're committing:",
    scope: '\nDenote the SCOPE of this change (optional):',
    // used if allowCustomScopes is true
    customScope: 'Denote the SCOPE of this change:',
    subject: 'Write a SHORT, IMPERATIVE tense description of the change:\n',
    body: 'Provide a LONGER description of the change (optional). Use "|" to break new line:\n',
    breaking: 'List any BREAKING CHANGES (optional):\n',
    footer: 'List any ISSUES CLOSED by this change (optional). E.g.: #31, #34:\n',
    confirmCommit: 'Are you sure you want to proceed with the commit above?',
  },

  scopes: [
    { name: 'component' },
    { name: 'util' },
  ],

  scopeOverrides: {
    fix: [{ name: 'merge' }, { name: 'style' }, { name: 'test' }, { name: 'hotfix' }],
  },

  allowCustomScopes: true,
  // skip any questions you want
  skipQuestions: ['breaking', 'footer'],
  subjectLimit: 100,
};

기본적으로는 gitmoji의 type을 사용한다. 이때 팀원들과 협의가 이루어져야 하는 최소한의 설정은 type, scopes, message, skipQuestions 정도로 보이고 기본을 바탕으로 우리 환경에 맞게 넣거나 빼면 되지 않을까 싶다. 특히 모노레포 환경에서 scopes 는 진짜 중요한 부분인것 같다.

여기까지 설정을 마치니 목표한 바는 달성 되었다.
결과

이제 여기서 한발 더 나아가 보자면 jira 같은 툴로 이슈를 트렉킹 한다고 할때 해당 일감 티켓이 커밋 메시지에 있으면 좋을것 같았다. (우리팀은 커밋 메시지에 포함 해서 작성 했다.)
이 경우 최종 커밋 메시지가 완료되기 직전에 기존 메시지에 티켓명을 포함 시켜 주면 될것 같다.
이미 husky hook을 사용하기 때문에 prepare-commit-msg hook을 이용해 shell script로 추가 해주면 된다.

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
echo 'Wait for attach jira issue ticket or branch name'

BRANCH_NAME=$(git symbolic-ref -q HEAD)
BRANCH_NAME=${BRANCH_NAME##*/}
ISSUE_TICKET=$(echo "$BRANCH_NAME" | sed -n 's/^\([A-Z]*-[0-9]*\)-\(.*\)$/\1/p')

echo $ISSUE_TICKET

if [ -n "$ISSUE_TICKET" ]; then

  echo "[Jira Issue Ticket: $ISSUE_TICKET]"
else
  ISSUE_TICKET=$(echo "$BRANCH_NAME")
  echo "[Branch: $BRANCH_NAME]"

COMMIT_MSG_FILE=$1
COMMIT_MSG=$(cat $COMMIT_MSG_FILE)

echo "$COMMIT_MSG  [$ISSUE_TICKET]" > $COMMIT_MSG_FILE

fi

위 스크립트는 간단하게 아래와 같이 동작한다.

  1. 현재 head 주소를 가져와
  2. 맨 마지막 브랜치 명만 때어 내고
  3. 브랜치에서 jira issue 티켓을 뽑아낸다.
  4. jira issue 티켓을 커밋 매시지에 포함 시킨다.
  5. jira issue 티켓이 없다면 현재 브랜치 명을 포함 시킨다.

아래 그림의 빨간 표시 부분 처럼 브랜치 명이 표시 된다.

그런데 여기서 vscode 를 이용해 commit 하시는 팀원 분들도 있다.

이 경우 아래의 extention을 설치 하면 커밋 메시지에 이모지를 사용 가능하다.

그러면 스마일 버튼이 생성되고 클릭하면 이모지 리스트가 나온다.

하지만 우리가 정의한 type에 맞는 이모지 들이 설정 되어 있지 않기 때문에 costomizing이 필요하다.
.vscode/settings.json에

{
  "gitmoji.addCustomEmoji": [
    { "emoji": "✨ feat:",
      "code": "",
      "description":"\tAdding a new feature" },
    { 
      "emoji": "🐛 fix:",
      "code": "",
      "description":"\tFixing a bug" },
    { 
      "emoji": "📝 docs:",
      "code": "",
      "description":"\tAdd or update documentation"
    },
    ...
  ],
  "gitmoji.showEmojiCode": true,
  "gitmoji.onlyUseCustomEmoji": true,
}

"gitmoji.onlyUseCustomEmoji": true, 설정을 켜주고 우리의 설정을 gitmoji의 정의 에 맞도록 추가해 준다.
그러면 아래 처럼 커스터마이징 이모지들이 표현되고 사용 가능하다.

결론

Convaltional Commits의 개요 부분을 보면 하나의 포맷으로 일관적인 메시지를 작성 하는것은 꽤나 장점이 크다. 특히 CI 단계에서 정형화 된 메시지는 자동으로 Change Log 작성하는데 도움을 줄것으로 보인다. 배포 시점에 일일이 커밋 메시지를 확인 해서 업데이트 노트를 작성했던 수고를 덜어 주지 않을까 싶다.

0개의 댓글