본문 바로가기
기타

PR시 미리보기 구현하기 (Github Actions)

by 유세지 2022. 11. 9.

여러 개발자가 팀으로 함께 개발을 하는 경우, 일반적으로 github를 통해 버전을 관리하게 됩니다. 실제 라이브 프로젝트를 배포하게 되는 main 브랜치가 있다고 하겠습니다. 보통 이 main 브랜치에서 파생하여 개발용 버전을 관리할 목적으로 사용하는 develop 브랜치를 두고 여기서 파생된 각 기능별 브랜치에서 실제 개발을 진행한뒤, 이를 develop 브랜치로 병합하여 관리합니다. 여기에 hotfix와 같은 기타 브랜치들이 더 추가되기도 하지만 우선 큰 줄기는 이렇습니다.

 

 

위에서 아래로 개발이 진행됩니다

 

 

이렇게 브랜치를 관리하는것 만으로도 프로젝트의 전체적인 그림을 파악하기에 좋지만, 아직은 몇 가지 문제가 남아있습니다. 예를 들어, 협업자의 코드를 볼 수는 있으나 그 결과를 눈으로 확인하려면 해당 브랜치로 이동하여 코드를 pull 받거나 해당 PR을 올린 사람이 따로 배포를 진행하여 결과물을 공유해주어야 합니다. 특히 프론트엔드의 경우 페이지가 시각적으로 어떻게 보이는지도 상당히 중요한 요소이기 때문에, 결과를 직접 확인하지 않고 코드만 리뷰하는 것은 충분하지 않다고 느꼈습니다.

 

일반적인 Pull Request로는 충분하지 않았습니다.

 

 

그렇다면, PR이 올라올때마다 자동으로 임시 배포가 진행되어 결과물을 눈으로 확인할 수 있다면 정말 좋을 것 같은데 어떻게 할 수 있을까요.

 

사실 이런 기능은 많은 클라우드 플랫폼에서 제공하고 있습니다. 대표적으로 Netlify나 Vercel등이 그렇습니다. 특정 레포지토리를 배포하기로 결정하면, 각 플랫폼의 봇이 PR을 감지하고 자동으로 배포하여 코멘트로 임시 링크를 알려줍니다.

 

Vercel 봇이 PR을 감지하고 자동 배포를 진행합니다.

 

그렇다면 이 bot들을 불러와서 사용하면 되지 않을까요?

 

아쉽게도 정책상의 이유로, 혹은 보안상의 이유로 organization내의 레포지토리에서는 이러한 bot의 자동 배포를 사용하지 못하는 경우가 있습니다. 이러한 기능들을 가진 bot들은 대부분 레포지토리에 대한 접근 권한을 필요로 하기 때문입니다. 그렇다면 깃허브가 지원하는 기능인 깃헙 액션(Github Actions)을 이용하여 이러한 봇들을 직접 만들어봅시다.

 

 

Github Actions

Automate your workflowfrom idea to production

 

깃헙 액션을 사용하면 이러한 작업 흐름을 자동화 할 수 있습니다. 먼저 우리가 필요한 기능들을 정리해봅시다.

 

1. 새로운 PR을 감지한다.

2. 감지된 PR을 바탕으로 빌드를 진행하고 배포한다.

3. 배포된 주소를 PR Comment를 통해 개발자에게 안내한다.

 

1번의 경우 깃헙 액션이 지원하는 메인 기능이고, 2번과 3번의 경우 GIthub Pages를 이용하면 가능할 것 같습니다. 간단히 설정해주겠습니다.

 

Github Actions

 

레포지토리에서 Actions 탭을 클릭하여 설정 페이지로 들어옵니다. 아직 설정된 액션이 없다면 위와 같은 초기 화면이 나타납니다. 소제목의 set up a workflow yourself 링크를 눌러 첫 액션을 생성해보겠습니다.

 

 

main.yml 편집 화면

 

 

repository_root/.github/workflows/main.yml 파일이 생성되고 있는 모습입니다. 편집기를 이용하지 않아도 해당 경로에 직접 새로운 파일을 생성하여 넣어주어도 똑같이 동작합니다. 오른쪽 사이드 메뉴에서는 이미 만들어진 다양한 액션들을 불러와서 사용할 수 있습니다. 일종의 라이브러리라고 생각하셔도 좋습니다.

 

이제 여기에 원하는 내용들을 구현해주시면 되는데, PR이 올라왔을때 배포 후 코멘트로 알려주는 기능까지 구현한 파일은 아래와 같습니다.

 

name: github action CI/CD 테스트용
on:
  pull_request:
    branches:
      - develop
      - master
    paths: "frontend/*"

defaults:
  run:
    working-directory: frontend

permissions:
  contents: read
  pages: write
  deployments: write
  id-token: write
  pull-requests: write

jobs:
  deployment:
    name: Deployment-action
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - uses: actions/checkout@v3
        with:
          ref: ${{ github.event.pull_request.head.sha }}
          
      - name: Setting node
        uses: actions/setup-node@v3.5.1
        with:
          node-version: 16
          cache: 'npm'
          cache-dependency-path: frontend/package-lock.json
          
      - name: npm install & build
        run: |
          npm install
          npm run build

      - name: configure github pages
        uses: actions/configure-pages@v2
        
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v1
        with:
          path: './frontend/build'
          
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v1

      - name: Format comment message
        id: format_comment_message
        uses: actions/github-script@v3
        with:
          github-token: ${{secrets.GITHUB_TOKEN}}
          script: |
          
            const deployURL = 'https://usageness.github.io/gitflow-test/';
            const comments = [
              `## Deploy Preview`,
              `🔥 **check your project preview here!** : `
            ].join('\n');
            
            core.setOutput('comment', comments);
            
      - name: comment PR
        uses: marocchino/sticky-pull-request-comment@v2
        with:
          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
          message: |
            ${{ steps.format_comment_message.outputs.comment}}[${{ steps.deployment.outputs.page_url }}](${{ steps.deployment.outputs.page_url }})

 

원하는 기능들이 어떻게 구현되었는지 하나씩 보겠습니다.

 

1. 새로운 PR을 감지한다.

레포지토리의 동작을 감지하는 부분은 상단의 on 부분입니다. on은 이벤트의 트리거가 될 동작을 정하는 속성으로, 현재 develop과 master 브랜치일때 frontend/ 경로에 변경이 생긴 Pull Request가 올라오면 아래의 이벤트들을 실행하게 됩니다.

 

on:
  pull_request:
    branches:
      - develop
      - master
    paths: "frontend/*"

 

이후의 작업을 위해 권한도 미리 설정해주었습니다.

 

permissions:
  contents: read
  pages: write
  deployments: write
  id-token: write
  pull-requests: write

 

 

2. 감지된 PR을 바탕으로 빌드를 진행하고 배포한다.

이 부분은 약간의 준비 과정이 필요합니다. 노드 프로젝트의 빌드를 진행해야 하므로 먼저 Node 환경 설치가 필요합니다.

 

jobs:
  deployment:
    name: Deployment-action
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - uses: actions/checkout@v3
        with:
          ref: ${{ github.event.pull_request.head.sha }}
          
      - name: Setting node
        uses: actions/setup-node@v3.5.1
        with:
          node-version: 16
          cache: 'npm'
          cache-dependency-path: frontend/package-lock.json

 

먼저 runs-on 옵션으로 실행 환경을 latest 버전의 ubuntu로 지정해줍니다. 덧붙여 이후에 github-pages를 사용할 예정이니 environment에 배포된 주소(deployment.outputs.page_url)을 함께 넣어주었습니다.

 

steps의 시작 부분에서 pull_request의 head로 들어간 뒤, 본격적으로 노드 환경을 설정해줍니다.

 

글을 작성하는 2022년 11월 기준으로 최신 버전인 setup-node 3.5.1 버전을 사용하여 노드 환경을 설정해줍니다. 이후의 빌드 작업 시 속도 단축을 목적으로 캐시를 사용해주기 위해 package.lock.json 파일을 cache-dependency-path로 설정해주었습니다.

 

캐시 설정 시 install & build 과정 속도 비교 (왼쪽 미설정, 오른쪽 설정)

 

 

실제로 설치 및 빌드 과정에 걸리는 시간이 29초에서 20초로 약간이나마 줄어든 모습입니다.

 

      - name: npm install & build
        run: |
          npm install
          npm run build

 

이제 프로젝트에 맞게 설치 명령어를 이용하여 모듈을 설치하고, 빌드해주시면 됩니다. 만약 yarn을 사용하셨다면 npm을 yarn으로 변경해주시면 됩니다.

 

      - name: configure github pages
        uses: actions/configure-pages@v2
        
      - name: Upload artifact
        uses: actions/upload-pages-artifact@v1
        with:
          path: './frontend/build'
          
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v1

 

배포의 마지막 단계입니다. github pages를 설정하고, 빌드된 파일의 경로 (제 경우엔 .frontend/build)를 입력해준뒤 deploy-pages를 이용하여 배포를 진행합니다.

 

 

 

3. 배포된 주소를 PR Comment를 통해 개발자에게 안내한다.

 

이제 배포까지 완료되었으니, 개발자에게 해당 내용을 안내해보겠습니다.

 

      - name: Format comment message
        id: format_comment_message
        uses: actions/github-script@v3
        with:
          github-token: ${{secrets.GITHUB_TOKEN}}
          script: |
          
            const comments = [
              `## Deploy Preview`,
              `🔥 **check your project preview here!** : `
            ].join('\n');
            
            core.setOutput('comment', comments);

 

github-script를 통해 PR 코멘트 메시지를 자바스크립트로 만들어주었습니다. comments 배열 안에 PR 코멘트로 표시 될 내용을 담아 comment라는 이름으로 내보내줍니다. 이후에 해당 steps의 id인 format_comment_messgae를 통해 이 output 값을 참조할 수 있습니다.

 

 

      - name: comment PR
        uses: marocchino/sticky-pull-request-comment@v2
        with:
          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
          message: |
            ${{ steps.format_comment_message.outputs.comment}}[${{ steps.deployment.outputs.page_url }}](${{ steps.deployment.outputs.page_url }})

 

comment PR 단계는 marocchino의 sticky-pull-request-comment 액션을 이용했습니다. GITHUB_TOKEN 속성에 토큰을 전달하여 접근 권한을 주고, message 속성에 위에서 내보냈던 steps.format_comment_messgae.outputs.commentsteps.deployment.outpus.page_url를 참조하여 메시지를 구성해주었습니다. 이때 GITHUB_TOKEN의 권한은 맨 위에서 설정했던 permission을 그대로 따라갑니다.

 

이렇게 yml파일 구성을 마쳤으니, 실제로 PR을 날려 테스트해보겠습니다.

 

 

결과

이제 설정해 준 브랜치(master, develop) 로 PR을 보내게 되면 아래처럼 github-actions bot이 코멘트를 남겨주게 됩니다.

 

이제 PR만 날려도, 그 결과를 바로 확인할 수 있습니다.

 

자동 배포 및 미리보기는 CI에 대한 내용을 알게 된 뒤로 꼭 한 번 적용하고 싶었던 기능이었는데, 이렇게 구현할 수 있게 되어 굉장히 뿌듯하네요. 개인 레포지토리가 아닌 organization에 적용하려면 몇 가지 제약 조건이 있긴 하겠지만 충분히 유용하게 쓸 수 있어 보입니다.

 

여기에 배포 뿐 아니라 테스트라던지, Lighthouse CI를 통해 페이지의 성능을 측정한다던지하는 추가적인 기능들을 덧붙여 응용할 수도 있어 꽤 재밌는 기능이 될 것 같습니다.

 

이 기능을 구현하며 삽질했던 내용을 정리했는데, 아래 링크에서 확인 가능합니다.

읽어주셔서 감사합니다.

 

 usageness/gitflow-test 삽질 정리

반응형

댓글