본문 바로가기

# Development/DevOps

[CI/CD] Github Actions로 Python CI 구축하기: Part1-Linting

Github Actions로 Python CI 구축하기: Part1-Linting

 

본 글을 읽기전에  CI/CD와 Github Actions에 대한 개념이 확실하지 않다면, 아래의 링크들을 읽어보길 바란다.

CI/CD

 

[CI/CD] CI/CD란 무엇인가?

CI/CD란 무엇인가? 소프트웨어 개발 및 배포를 자동화하여 효율적으로 개발 및 배포 프로세스를 관리하는 방법론이다. CI (Continuous Integration) Continuous Integration: 지속적 통합 CI는 개발자들이 코드를

yoon001.tistory.com

Github Actions

 

[CI/CD] GitHub Actions란?

Github Actions란? Github Actions는 소프트웨어 개발과 배포를 자동화하는 통합 서비스이다. 소프트웨어 개발 라이프사이클 안에서 Pull Request, Push 등의 이벤트 발생에 따라 자동화된 작업을 진행할 수

yoon001.tistory.com

 

Linting이란?

Linting은 소스 코드에서 잠재적인 오류나 스타일 규칙 위반을 찾아내고 보고하는 프로세스를 가리키는 용어이다.  Linting은 오타나 문법 오류와 같은 기본적인 실수를 찾아내어 높은 품질의 코드를 작성하도록 도와준다. 

 

파이썬에서 linting은 보통 'PEP 8'이라고 불리는 파이썬 스타일 가이드를 준수하는지 확인한다.

 

일반적으로 코드를 작성하는 동안에는 편집기나 통합 개발 환경 (IDE)과 같은 도구를 통해 실시간으로 linting 결과를 확인하고, 파이썬에서는 PyLint, Flake8, Pyflakes 등의 패키지 도구를 사용하여 자동화된 방식으로 코드를 검사할 수 있다.

 

코드 파일 준비

CI/CD 테스트를 위해 만든 repository다. Frok로 복사해서 앞으로 진행될 과정들을 테스트 해볼 수 있다.

 

GitHub - sokuli-bit/study-ci-cd: CI/CD 테스트를 위한 레포지토리

CI/CD 테스트를 위한 레포지토리. Contribute to sokuli-bit/study-ci-cd development by creating an account on GitHub.

github.com

테스트를 실행 할 main.py 파일에는 함수 2개가 담겨있다.

### main.py

import math
import os


def add(a, b) -> int:
    return math.floor(a + b)


def to_sentence(s) -> str:
    s = s.capitalize()

    if s.endswith("."):
        return s
    else:
        return s + "."

 

 

Github Actions CI(Linting) 구축 방법

Workflow 생성

워크플로우는 Github Actions의 핵심이다.

.github/workflows 디렉토리에 워크플로우 YAML 파일을 생성하여 작업을 정의한다.

 

간단한 워크플로우 예시를 작성해보자. Github Actions에 들어가보면 기본으로 제공하는 YAML 파일 템플릿들이 있다.

 

 

 

Python application을 선택하면 다음과 같은 yml 파일이 자동 생성되는데,

해당 파일은 Python 프로젝트의 Lint 테스트(flake8)유닛 테스트(pytest) 실행하는 Actions 파일이다.

 

name: Python Application  # 프로젝트의 이름을 정의

on:
  push:
    branches: [ "main" ]  # "main" 브랜치로 push가 발생할 때 이 액션을 실행
  pull_request:
    branches: [ "main" ]  # "main" 브랜치로 pull request가 발생할 때 이 액션을 실행

permissions:
  contents: read  # 이 액션이 읽기 권한을 가지도록 정의

jobs:
  build:  # "build" 라는 작업을 정의

    runs-on: ubuntu-latest  # Ubuntu 환경에서 실행

    steps:  # 작업 단계를 정의
    - uses: actions/checkout@v3  # GitHub 리포지토리를 체크아웃하여 사용
    - name: Set up Python 3.10  # Python 3.10을 설정
      uses: actions/setup-python@v3  # Python 설정 액션 사용
      with:
        python-version: "3.10"  # Python 버전을 3.10으로 지정
    - name: Install dependencies  # 의존성 설치
      run: |  # 아래 스크립트를 실행
        python -m pip install --upgrade pip  # pip 업그레이드
        pip install flake8 pytest  # flake8과 pytest 설치
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi  # requirements.txt 파일이 있으면 해당 파일에 명시된 의존성 설치
    - name: Lint with flake8  # flake8을 사용하여 코드 스타일과 오류 검사
      run: |  # 아래 스크립트를 실행
        # stop the build if there are Python syntax errors or undefined names
        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics  # Python 구문 오류 또는 정의되지 않은 이름이 있을 경우 빌드 중지
        # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
        flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics  # 모든 오류를 경고로 처리하도록 설정. GitHub 편집기는 127자의 너비를 가짐
    - name: Test with pytest  # pytest를 사용하여 테스트 실행
      run: |  # 아래 스크립트를 실행
        # [테스트 스크립트는 이 자리에 들어와야 함]

 

 

set up a workflow yourself에 들에 들어가면,

코드가 통합되기전 진행 되었으면 하는 기능들(step)을 선택해서 블럭 쌓듯이 workflow를 만들수도 있다.

 

 

Marketplace에서 원하는 기능을 검색한뒤, 

 

 

 

작성되어 있는 step 스크립트를 복사, 붙여넣기해서 workflow를 만들 수 있다.

아래와 같은 방법으로 여러개의 step을 추가 할 수 있다.

 

 

Workflow를 작성하고 나면, 정의한 Event가 발생할 때 작성한 Workflow가 실행되고,

Actions 탭에서 Workflow 실행 성공 여부를 확인 할 수 있다.

 

 

Github Actions에서 주로 사용하는 도구

Black

Black는 Python 코드 포맷터로, 코드의 일관성을 유지하고 스타일 가이드를 준수하도록 도와준다.

Black은 코드를 검사하고 필요한 경우 자동으로 포맷하여 코드 스타일을 일관성 있게 유지한다.

 

black

The uncompromising code formatter.

pypi.org

 

Flake8

Python 코드의 문법적 오류와 스타일을 검사하는 도구다.

코드 스타일 가이드를 준수하지 않거나 구문 오류가 있는 경우 경고 및 에러를 출력한다.

 

flake8은 자체도 여러 개의 도구들을 결합한 것이다

  •  pycodestyle: PEP 8 스타일 가이드 기반
  •  pyflakes: 코드 복잡도와 버그를 검사
  •  mccabe: 함수와 변수의 타입을 검사
 

flake8

the modular source code checker: pep8 pyflakes and co

pypi.org

 

Mypy

mypy는 정적 타입 검사 도구로, Python 코드의 변수와 함수의 타입을 검사하여 타입 관련 오류를 찾아낸다.

 

Python은 동적 타입 언어로, 변수의 타입을 런타임 시점에서 결정한다.

하지만 mypy는 타입 힌트를 통해 코드에 명시적으로 타입을 정의하고, 이를 기반으로 정적으로 타입을 검사한다.

 

mypy를 사용하여 타입 검사를 수행하면 코드의 가독성을 향상시키고 디버깅 시간을 단축하여 안정성을 높일 수 있다.

 

mypy

Optional static typing for Python

pypi.org

 

Isrot

isort는 Python 코드의 import문을 자동으로 정렬해주는 도구다.

코드의 가독성을 높이고, 표준화된 import 스타일을 유지하며, import문의 순서를 일관성 있게 관리할 수 있도록 도와준다. 

 

isort는 코드를 분석하여 import문을 그룹화하고, 내장 모듈, 서드파티 패키지, 프로젝트 내의 모듈 순서를 정리하여 재배치한다.

 

이를 통해 복잡한 import문을 간결하고 일관성 있게 관리할 수 있다.

 

isort

A Python utility / library to sort Python imports.

pypi.org

 

커스텀 Workflow

아래는  CI 테스트를 위해  worklfow를 정의한  .yml 파일이다.

각각 라인에 대한 설명은 주석으로 적어두었다.

### python-lint.yml
# 워크플로우 이름
name: (PR) Format Python Code

# 워크플로우를 실행할 이벤트 설정
on:
  push:
    branches: [ "master" ]  # "master" 브랜치로 push가 발생할 때 이 액션을 실행
  pull_request:
    branches: [ "master" ]  # "master" 브랜치로 pull request가 발생할 때 이 액션을 실행

# 작업 정의
jobs:
  python-code-format:
    runs-on: ubuntu-20.04 # Ubuntu 20.04 환경에서 실행

    # 실행할 단계 정의
    steps:
      # GitHub 리포지토리를 체크아웃 (클론)
      - name: Checkout code
        uses: actions/checkout@v2

      # Python 환경 설정
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: "3.10" # Python 3.10 버전 사용
          architecture: "x64" # 64비트 아키텍처 사용

      # Python 버전 확인
      - name: Display Python version
        run: python --version # Python 버전 표시

      # 필요한 Python 패키지 설치
      - name: Install packages
        run: pip install black isort autopep8

      # 코드 포맷팅 작업 수행
      - name: Formatter
        run: |
          black . # Black를 사용하여 코드 포맷팅
          autopep8 --recursive --in-place --aggressive --aggressive . # autopep8를 사용하여 코드 포맷팅
          isort . # isort를 사용하여 코드 포맷팅

      # Pull Request 생성
      - name: Create Pull Request
        uses: peter-evans/create-pull-request@v3
        with:
          commit-message: Auto code format # 커밋 메시지
          title: Fixes by format action # 풀 리퀘스트 제목
          body: This is an auto-generated PR with fixes. # 풀 리퀘스트 본문
          labels: automated pr # 레이블
          branch: python-code-format-patches # 새로운 브랜치 이름

 

위에서 모듈등을 통해 자동 변경된 사항들을 Pull request를 통해 반영되도록 작업이 작성되었다.

혹시 Pull Request가 아니라 Commit 으로 반영하게 하고 싶다면 아래의 부분을 주석처리 하고,

      # Pull Request 생성
      - name: Create Pull Request
        uses: peter-evans/create-pull-request@v3
        with:
          commit-message: Auto code format # 커밋 메시지
          title: Fixes by format action # 풀 리퀘스트 제목
          body: This is an auto-generated PR with fixes. # 풀 리퀘스트 본문
          labels: automated pr # 레이블
          branch: python-code-format-patches # 새로운 브랜치 이름

 

다음과 같이 Commit 명령어를 입력해주면 된다.

      ## 변경사항 Commit
      - name: Commit format changes
        run: |
          git config --local user.email "action@github.com"
          git config --local user.name "GitHub Action"
          git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}
          git commit -am "Automated format fixes"
          git push

 

CI 실행 

이제 코드를 수정하고, main 브랜치에 Push 하면 위에서 설정한 Workflow를 실행한다.

실행된 Workflow 결과는 Github 브랜치 Actions 탭에서 확인 할 수 있다.

 

권한설정 에러 

처음 CI Wrokflow 중 isort 변경 사항을 코드에 반형하는 push isort changes 과정에서 "Permission to sokuli-bit/study-ci-cd.git denied to github-actions[bot]" 에러가 발생 할 수 있다.

 

이유는 GitHub Actions의 기본적인 GITHUB_TOKEN 해당 저장소에 대한 push 권한을 가지고 있지 않기 때문이다.

 

 

깃헙 공식 문서에  GITHUB_TOKEN이 Workflow에서 코드를 수정 할 수 있는 권한을 주는 방법이 나와있다.

 

Automatic token authentication - GitHub Docs

GitHub provides a token that you can use to authenticate on behalf of GitHub Actions.

docs.github.com

 

Setting > Actions > General > WorkFlow permissions

 

설명에 따라 위의 순서로 페이지에 들어가면 Read repository contents and packages permissions가 선택되어 있을텐데 아래의 이미지처럼 위의 Read and write perissions로 바꿔주고 다시 push 하면 commit이 잘 이루어진다.

 

 

마무리

이 글에서는 Github Actions를 활용하여 Python 프로젝트에서 Linting을 자동화하는 방법을 알아보았다. 코드 스타일 오류를 자동으로 검출하고 수정하는 것은 프로젝트의 일관성을 유지하고 버그를 사전에 방지하는 데 매우 유용하다.

 

다음 글에서는 Github Actions를 활용하여 Python 프로젝트에서 테스트 자동화를 설정하는 방법을 정리해보려고 한다.

https://yoon001.tistory.com/85?category=1060034

 

[CI/CD] Github Actions로 Python CI 구축하기: Part2-Testing

Github Actions로 Python CI 구축하기: Part2-Testing 테스트는 소프트웨어 개발과 배포에서 핵심적인 부분으로, 코드의 품질을 보장하고 안정성을 높이는 과정이다. 이 글에서는 테스트 코드를 작성하는

yoon001.tistory.com