본문 바로가기
프로그래밍/안드로이드

[Android] 깃허브 액션을 통해 자동으로 릴리즈 태그 생성하기 (커밋 기록 포함)

by dev_gyu 2024. 12. 7.
728x90

내가 자주 사용하는 CICD 툴인 Bitrise 에서는 배포를 위한 트리거 방식이 여러 가지가 존재한다.

  1. Branch PR 이 올라오는 경우
  2. Branch Push 가 되는 경우
  3. 특정 Tag 가 생성되는 경우

내 프로젝트의 경우 CI/CD 를 위한 Branch 명이 자주 바뀌는 관계로 Branch 명에는 정규표현식을 사용하여 특정 문자열로 시작하는 브랜치인 경우 무조건 CI/CD 가 실행되게 하였었으나, 이러는 경우 정규표현식에 포함되는 다른 브랜치도 트리거 해버려서 의도치 않게 배포를 해버리는 경우가 종종 있었다.

 

이를 해결하기 위해 나는 3번. 즉, 특정 Tag 를 통해 배포를 하기로 마음을 먹었다.

 

우선 나는 테드팍님 (박상권) 님의 블로그 를 참고하였는데, 이곳에서는 Branch 가 Push 되었을때 해당 커밋 내용과 버전만을 기록하고 있었지만 나의 경우 조금 더 손을 봐 A (Feature) -> B (Master) 브랜치로 PR 이 병합 되었을 때, 병합 전 B 브랜치의 버전과 A 브랜치 사이에 있었던 모든 커밋들을 Release Tag 에 기록되게 만들었다.


# 생성 방법

이제 대충 설명을 모두 마쳤으니 릴리즈 태그 생성용 워크플로우를 만들어보도록 하자.

[안드로이드 관점에서 작성하여으니 혹시나 다른 개발자분들은 조금 변형해서 쓰시면 될 것 같습니다.]

 

 

우선 Github Repository -> Actions 로 들어가 좌측 상단의 New workflow 를 생성해준다.

그 다음 Simple workflow 의 Configure 를 통해 커스텀 워크플로우를 구현하기 위한 준비를 하고, 모든 내용을 지운 뒤 다음과 같이 코드를 추가해준다.

# 이름은 자유롭게 설정하면 됩니다
name: Release Tag Creator

on:
 pull_request:
    types:
      - closed
      
permissions:
  contents: write

 

나의 경우 PR 이 병합되었을 경우에만 이 워크플로우를 실행하기를 원하니 on 에 PR 이 닫혔을 때 워크플로우가 실행되도록 해준다.

types 로는 병합 하나만을 확인이 불가능하고 닫힘만을 확인할 수 있기에, 이것에 대한 설정은 job 을 실행할 때 조건으로 추가해줄 것이다.

 

추가로 permissions: contents: write 를 추가해줘야 자동적으로 릴리즈 태그를 생성해줄 수 있기 때문에, 이는 필수적으로 등록이 필요하다.

 

위의 모든 작업을 마쳤다면 아래의 코드를 복사해주자.

jobs:
  base-branch-release:
  	# 이곳에서 베이스 브랜치가 main 으로 시작하고, merge 되어야 실행되게 설정함.
    if: ${{ startsWith(github.event.pull_request.base.ref, 'main') && github.event.pull_request.merged == true }}
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
          
      - name: Base 및 Head Sha 가져옴
        run: |
          git fetch origin ${{ github.event.pull_request.base.sha }}
          git fetch origin ${{ github.event.pull_request.head.sha }}
          echo "BASE_SHA=${{ github.event.pull_request.base.sha }}" >> $GITHUB_ENV
          echo "HEAD_SHA=${{ github.event.pull_request.head.sha }}" >> $GITHUB_ENV
          
      - name: Base Branch 로 체크아웃
        uses: actions/checkout@v2
        with:
          ref: ${{ github.event.pull_request.base.ref }}
          
      # versionName 으로 추출하도록 설정하였기 때문에, 변형이 필요하다면 이곳 수정
      - name: 버전 정보 추출
        run: |
          echo "브랜치에서 앱 버전 정보를 가져옵니다."
          PR_VERSION_NAME=$(grep -oP '(?<=versionName\s=\s").*?(?=")' app/build.gradle.kts)
          echo "PR_VERSION_NAME=$PR_VERSION_NAME" >> $GITHUB_ENV

      - name: 릴리즈 노트 (커밋 사안들) 생성
        run: |
          EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
          # Base Branch Log 및 Head Branch Log 가져오기 (병합 당시)
          # oneline 으로 커밋 로그를 한 줄로 요약하여 출력 
          CHANGES=$(git log --oneline ${{ env.BASE_SHA }}..${{ env.HEAD_SHA }} )
          # Merge Branch 문장 찾고 마지막 단어만 추출, 그리고 샾 세개를 붙여 강조표시
          CHANGES=$(echo "$CHANGES" | sed '/^Merge Branch/ s/.*\s\([^ ]*\)$/### \1/')
          # 샾 세개로 시작하지 않는 커밋 내역 각 줄 앞에 - 생성
          CHANGES=$(echo "$CHANGES" | sed '/^###/! s/^/- /')
          RELEASE_BODY="## What's Changed"$'\n'"$CHANGES"
          {
            echo "RELEASE_BODY<<$EOF"
            echo "$RELEASE_BODY"
            echo "$EOF"
          } >> $GITHUB_ENV

      - name: 깃허브 릴리즈 태그 생성
        uses: actions/create-release@v1
        env: 
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with: 
          tag_name: ${{ env.PR_VERSION_NAME }} 
          release_name: Release ${{ env.PR_VERSION_NAME }} 
          body: ${{ env.RELEASE_BODY }}

 

상세한 주석들은 내부 코드에 설정해두었으므로 이를 참고하자.


# 최종본

name: Release Tag Creator

on:
 pull_request:
    types:
      - closed
      
permissions:
  contents: write 
  
jobs:
  base-branch-release:
    if: ${{ startsWith(github.event.pull_request.base.ref, 'main') && github.event.pull_request.merged == true }}
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
        with:
          fetch-depth: 0
          
      - name: Base 및 Head Sha 가져옴
        run: |
          git fetch origin ${{ github.event.pull_request.base.sha }}
          git fetch origin ${{ github.event.pull_request.head.sha }}
          echo "BASE_SHA=${{ github.event.pull_request.base.sha }}" >> $GITHUB_ENV
          echo "HEAD_SHA=${{ github.event.pull_request.head.sha }}" >> $GITHUB_ENV
          
      - name: Base Branch 로 체크아웃
        uses: actions/checkout@v2
        with:
          ref: ${{ github.event.pull_request.base.ref }}
          
      - name: 버전 정보 추출
        run: |
          echo "Release 브랜치에서 앱 버전 정보를 가져옵니다."
          PR_VERSION_NAME=$(grep -oP '(?<=versionName\s=\s").*?(?=")' app/build.gradle.kts)
          echo "PR_VERSION_NAME=$PR_VERSION_NAME" >> $GITHUB_ENV

      - name: 릴리즈 노트 (커밋 사안들) 생성
        run: |
          EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
          # Base Branch Log 및 Head Branch Log 가져오기 (병합 당시)
          # oneline 으로 커밋 로그를 한 줄로 요약하여 출력 
          CHANGES=$(git log --oneline ${{ env.BASE_SHA }}..${{ env.HEAD_SHA }} )
          # Merge Branch 문장 찾고 마지막 단어만 추출, 그리고 샾 세개를 붙여 강조표시
          CHANGES=$(echo "$CHANGES" | sed '/^Merge Branch/ s/.*\s\([^ ]*\)$/### \1/')
          # 샾 세개로 시작하지 않는 커밋 내역 각 줄 앞에 - 생성
          CHANGES=$(echo "$CHANGES" | sed '/^###/! s/^/- /')
          RELEASE_BODY="## What's Changed"$'\n'"$CHANGES"
          {
            echo "RELEASE_BODY<<$EOF"
            echo "$RELEASE_BODY"
            echo "$EOF"
          } >> $GITHUB_ENV

      - name: 깃허브 릴리즈 태그 생성
        uses: actions/create-release@v1
        env: 
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with: 
          tag_name: ${{ env.PR_VERSION_NAME }} 
          release_name: Release ${{ env.PR_VERSION_NAME }} 
          body: ${{ env.RELEASE_BODY }}

 

 

# 결과물

728x90