TIL#28 GitHub Readme 자동 업데이트 [GitHub Actions]

박감자·2024년 10월 27일

TIL

목록 보기
28/34

시작 전 TMI

깃허브는 날 늘 힘들게 한다ㅋㅋㅋ
저번에는 계정 문제로 날 시험에 들게 하더니 액션즈 이해하는데도 반나절이 걸렸다. 챗지피티는 GOAT다

GitHub Actions란

워크플로우 자동화를 위해 자주 사용되는 도구로 자동 배포, Testing, 나의 경우 자동 리드미 업데이트용 등으로 편리하게 사용이 가능하다.

더 자세한 설명은 다른 분의 블로그 글이 정리를 잘 해주셨다.

Readme 업데이트 자동화

푼 알고리즘 문제가 50개가 넘어가는 시점에서 리드미를 수동으로 업데이트를 하고 있었는데 이 과정이 너무 귀찮아서 자동화를 하고 싶었다. 근데 아는 정보가 없어 챗지피티에게 물어본 결과 GitHub Actions에 yml 파일을 추가해주는 것으로 내가 원하는 것이 가능하다고 알려주었다.

0. 현재 수동적인 나의 워크 플로우

내 알고리즘 리포지토리는 백준허브를 이용하여 프로그래머스에서 문제를 풀때 자동으로 커밋 시키는 extension을 사용 중이다. 커밋 후에 Readme에 그날 푼 문제의 레벨, 깃허브 링크, 풀어본 횟수, 해결 여부를 일일이 추가하는 중이었다.

근데 푼 문제가 늘수록 이 작업이 너무 귀찮았고 자동화를 시키기로 했다.

1. 워크플로우 디렉토리/파일 만들어주기

우선 현재 알고리즘 리포지터리에 워크플로우 디렉토리와 업데이트 파일을 만들어준다.

2. yml 파일 내용 작성

코드를 사실상 다 이해하지는 못했지만 무슨 흐름으로 작동하는지 대충 감 잡은 걸 토대로 아래와 같은 파일을 완성 시켰다. 설명은 아래에 계속해서 할 예정

name: Update README

on:
  push:
    branches:
      - main  # Adjust if using a different default branch
    paths-ignore:
      - '**/*.yml'  # Exclude pushes to YAML files, including this workflow file

jobs:
  update-readme:
    if: contains(github.event.head_commit.message, '[level')  # Only run if commit message includes "[level"
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Count solutions and update README
        run: |
          # Define the README file path
          README_FILE="README.md"

          # Add introductory content
          echo "# 알고리즘 풀이 ![js](https://img.shields.io/badge/JavaScript-F7DF1E?style=for-the-badge&logo=JavaScript&logoColor=black)" > $README_FILE
          echo "> 백준허브로 연동된 자동 커밋 리포지토리 [BaekjoonHub](https://github.com/BaekjoonHub/BaekjoonHub)." >> $README_FILE
          echo ">" >> $README_FILE
          echo "> _Readme는 문제 번호에 따라 자동 업데이트 합니다._" >> $README_FILE
          echo "" >> $README_FILE  # Blank line for spacing
          echo "# 프로그래머스 문제" >> $README_FILE

          # Append each level section
          for level in 0 1 2; do
            echo "" >> $README_FILE
            echo "## Level $level." >> $README_FILE
            echo "| 난이도 | 코드 (내 풀이) | 풀어본 횟수 | 해결여부 |" >> $README_FILE
            echo "| :----: | :-------------: | :-------: | :--: |" >> $README_FILE
            
            # Find each problem in the level directory
            level_folder="프로그래머스/$level"
            for problem in $(ls "$level_folder"); do
              problem_path="$level_folder/$problem"
              problem_name=$(basename "$problem")
              commit_count=$(git rev-list --count HEAD -- "$problem_path")
              problem_link="https://github.com/chay140/Algorithms/tree/main/$problem_path"
              
              # Append the problem entry to the README
              echo "| Lv.$level | [$problem_name]($problem_link) | $commit_count | O |" >> $README_FILE
            done
          done

          # Configure Git and commit the README update
          git config --global user.name "github-actions[bot]"
          git config --global user.email "github-actions[bot]@users.noreply.github.com"
          git add $README_FILE
          git commit -m "Auto-update README with latest problem stats"
      
      - name: Push changes
        run: git push
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

2-1) name / on

  • name에서는 워크플로우의 이름을 지정해주는 것으로 나는 Update README로 지정을 해주었다.
  • on에서는 무슨 이벤트 때 이를 실행할지 지정해주는 것이다. 즉 Trigger를 정해주는 역할.

문제가 커밋될때마다 워크플로우 파일이 실행될 수 있도록 main브랜치에 push될때마다 실행시키도록 했다.

on:
  push:
    branches:
      - main
    paths-ignore:
      - '**/*.yml' 

위에 코드에는 조금의 하드 코딩이 들어가긴 했는데, 우선 이 yml파일이 업데이트 될때는 자동화를 실행시키지 않도록 지정해주었다.

백준허브로 커밋을 할 때 외에는 직접적으로 커밋을 할 일은 없기에 저렇게 지정해주었다. 이를 지정해주지 않으면 yml파일을 변경해서 커밋해도 위의 워크플로우가 실행되는데 리드미에 추가할 내용이 없으니 에러가 뜬다.

처음에 이거 지정 안했다가 워크플로우에 아래와 같은 에러가 떴다

yml 파일 작성해서 커밋한거였는데...ㅎ... 그래서 path-ignore는 불필요한 워크플로우를 줄여줄 수 있다.

2-2) jobs

이제 무슨 작업을 할지 지정해주는 jobs를 마저 써준다.

jobs:
  update-readme:
    if: contains(github.event.head_commit.message, '[level')
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Count solutions and update README
        run: |
          # 상세 내용은 위의 코드와 동일
      
      - name: Push changes
        run: git push
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}      
  • update-readme라는 이름의 job를 지정해준 것
  • if에는 혹시 자동 커밋 외의 다른 커밋이 있을 시 워크플로우 실행을 방지하기 위해 백준허브 커밋 메세지 패턴을 따를대만 실행하도록 지정해주었다.
  • runs-on는 실행할 OS를 지정해주는 것으로 자주 사용 되는 ubuntu-latest를 사용했다. 그래서 run시 언어도 shell 커맨드가 된다.
  • steps는 액션의 이름을 지정해주고 각 커맨드가 특정 역할을 하다도록 나눈 것이라 생각하면 편하다.
    • Checkout repository 는 GitHub Actions가 코드를 실행할때 내 리포지토리에 대한 접근을 필요로 하는데 이를 가능케 해준다.

      추가적으로 fetch-depth: 0을 적어줌으로써 여러번 푼 문제가 있다면 가장 최근 커밋 외에도 모든 커밋의 수를 알 수 있도록 지정했다.
      하지만 이 방법은 결국 모든 커밋을 읽는 과정을 추가해준 것과 마찬가지이기에 액션의 런타임을 증가시킨다고 해서, 나중에 최적화를 해봐야할 것 같다 (커밋이 늘어날 수록 문제가 생길것 같기 때문)
    • Count solutions and update README 이 부분이 필요한 리드미 작성해주는 부분. run: |부분은 여러 shell 커맨드를 실행시켜주는 역할을 한다.
    • Push Changes에서는 작성한 리드미를 push하는 작업을 수행한다.

      이 작업을 수행할 때는 GITHUB_TOKEN을 제공해주어야 하는데 따로 적을 필요는 없고 자료 그대로 작성해서 적용시켜도 잘 작동한다.

2-3) 리드미 구조 작성

이 부분에서는 리드미의 경로를 지정해주고 필요한 내용을 작성해주면 된다.

2-3-1) 리드미 인트로

나의 경우에는 인트로 부분이 있어 이를 아래와 같이 지정해주었고

# Add introductory content
echo "# 알고리즘 풀이 ![js](https://img.shields.io/badge/JavaScript-F7DF1E?style=for-the-badge&logo=JavaScript&logoColor=black)" > $README_FILE
echo "> 백준허브로 연동된 자동 커밋 리포지토리 [BaekjoonHub](https://github.com/BaekjoonHub/BaekjoonHub)." >> $README_FILE
echo ">" >> $README_FILE
echo "> _Readme는 문제 번호에 따라 자동 업데이트 합니다._" >> $README_FILE
echo "" >> $README_FILE  # Blank line for spacing
echo "# 프로그래머스 문제" >> $README_FILE

리드미에서 이 부분은 아래와 같이 보여진다 (다크모드 기준).

2-3-2) 레벨별 표 만들어주기

# 각 레벨별로 표 구성
for level in 0 1 2; do
	echo "" >> $README_FILE
	echo "## Level $level." >> $README_FILE
	echo "| 난이도 | 코드 (내 풀이) | 풀어본 횟수 | 해결여부 |" >> $README_FILE
    echo "| :----: | :-------------: | :-------: | :--: |" >> $README_FILE
            
    # 각 레벨 폴더 접근해서 필요 데이터 추출
    level_folder="프로그래머스/$level"	# 폴더명
    for problem in $(ls "$level_folder"); do
    	problem_path="$level_folder/$problem"	# 문제 경로
        problem_name=$(basename "$problem")		# 문제 명
        commit_count=$(git rev-list --count HEAD -- "$problem_path")	# 커밋 횟수
        problem_link="https://github.com/chay140/Algorithms/tree/main/$problem_path"	# 문제 링크
              
        # 리드미에 추가
        echo "| Lv.$level | [$problem_name]($problem_link) | $commit_count | O |" >> $README_FILE
	done
done

위의 코드는 아래의 표가 된다.

커밋횟수도 잘 나오고 링크도 잘 첨부된다.

2-3-3) 커밋 변수/환경 지정

마지막으로 깃허브 액션 봇 정보를 이용해 커밋을 해주면 된다.

# Configure Git and commit the README update
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git add $README_FILE
git commit -m "Auto-update README with latest problem stats"

3. 환경설정


하지만 처음에 이를 실행했을때 워크플로우 실행이 실패했는데 해당 이벤트를 클릭해서 확인해보니

push에서 unable to access가 뜨는 것을 발견!

Setting > Actions > General에 들어가서

Workflow permissions를 찾아서 설정을 read & write로 변경해준 후 저장해주면 된다.

4. 작동 확인

이제 프로그래머스 들어가서 문제를 하나 풀어보면
리드미에 자동으로 푼 문제를 업데이트 해준다. (만세!!)

내 알고리즘 리포지토리 링크.

마치며...

정말이지 이해하는데 오래 걸린 자동화이지만, 활용하면 진짜 편할 것 같아서 시간 날때 계속 업데이트 해볼 예정이다.

profile
코딩하는 감자

0개의 댓글