개발/파이썬

poetry와 github actions를 활용한 파이썬 라이브러리 배포 자동화

seonu._.jang 2024. 4. 13. 18:38
반응형

파이썬 개발을 하다 보면 필요한 라이브러리를 pip install 커맨드를 통해 쉽게 다운받아서 활용합니다. pandas, pydantic, fastapi 등 유명한 라이브러리가 많습니다. 이렇게 라이브러리를 설치해 사용하기도 하지만, 때로는 직접 라이브러리를 만들어서 배포하고 싶을 때가 있습니다. 파이썬에서는 어떻게 다른 사람들이 사용할 수 있는 라이브러리를 만들어 배포할까요?

오늘은 실습을 통해 직접 파이썬 라이브러리를 만들고, Github Actions를 이용해 라이브러리의 버전이 변경될 때마다 자동으로 배포하는 시스템을 만들어보겠습니다.

poetry 소개

poetry는 의존성 관리 및 패키지 배포를 손쉽게 잘할 수 있도록 도와주는 도구입니다. poetry를 사용하지 않더라도 requirements.txt에 직접 사용한 라이브러리를 명시해서 의존성 관리를 할 수 있지만 수동으로 관리할 경우 실수하기 쉽고 라이브러리 변경이 생길 때마다 번거로운 과정을 거쳐야 합니다. 또한 배포를 위해서 setup.py를 직접 작성해 주어야 합니다.

poetry는 이러한 번거로운 과정을 최소화하여 패키지를 관리해 주고 setupy.py 같은 추가적인 파일 작성이나 라이브러리 없이 단순한 커맨드 만으로 빌드 및 배포를 쉽게 가능하게 합니다. 사용자는 poetry add를 통해 라이브러리 설치, poetry build를 통해 빌드, poetry publish를 통해 배포를 할 수 있습니다.

poetry 공식 홈페이지

간단한 랜덤 닉네임 생성 라이브러리 제작하기

1. poetry 설치

poetry를 설치하기 위해서는 아래 명령어를 입력합니다.

맥,리눅스/WSL

curl -sSL https://install.python-poetry.org | python3 -

윈도우 (파워쉘)

(Invoke-WebRequest -Uri https://install.python-poetry.org -UseBasicParsing).Content | py -

설치가 완료되었다면 아래 명령어를 입력해 정상적으로 poetry가 설치되었는지 확인합니다.

poetry --version

아래와 같은 이미지가 나타나면 정상적으로 설치가 완료된 것입니다.

2. poetry 프로젝트 세팅

라이브러리를 만드실 디렉토리를 하나 생성하고 아래의 명령어를 입력해줍니다.

poetry init

질문에 나오는 정보에 필요한대로 답하시면 됩니다. 저는 아래와 같이 세팅하였습니다.

저희는 라이브러리를 만들어서 배포할 것이기 때문에 이름이 중요합니다. Pypi 에서 본인이 만들고자 하는 라이브러리가 존재하지 않는 것을 확인하고 만드는 것을 추천드립니다.

입력을 끝마치면 pyproject.toml이라는 파일이 생성되는데 여기서 의존성 관리가 이루어지게 됩니다. (개발 도구들의 설정 관리가 이루어지기도 하는데 여기서 해당 부분은 넘어가겠습니다.)

3. 라이브러리 개발

아래와 같이 간단하게 한국어로 된 자동 닉네임을 생성하기 위한 라이브러리를 만들어 보았습니다. 👉 Github 커밋 보기

# koname/__init__.py

import random

ADJECTIVES = [
    "영롱한",
    "빛나는",
    "반짝이는",
    "빛나는",
    "귀여운",
    "멋진",
    "아름다운",
    "화려한",
    "행복한",
    "행운의",
    "고운",
    "예쁜",
    "화난",
    "정열적인",
    "무서운",
    "무시무시한",
    "감동적인",
    "감격적인",
]

NOUNS = [
    "호랑이",
    "사자",
    "코끼리",
    "기린",
    "코알라",
    "팬더",
    "늑대",
    "여우",
    "오소리",
    "청솔모",
    "다람쥐",
    "토끼",
    "사슴",
    "햄스터",
    "고양이",
    "강아지",
    "송아지",
    "족제비",
]


def generate_nickname(digits: int = 4):
    adjective = random.choice(ADJECTIVES)
    noun = random.choice(NOUNS)
    number = random.randint(0, 10**digits - 1)
    return f"{adjective}{noun}{number:0{digits}d}"

만드신 프로젝트는 본인의 Github에 등록해줍니다.

4. Pypi 가입하기

파이썬 라이브러리는 Pypi라는 파이썬 공식 레포지토리를 통해 배포됩니다. 해당 레포지토리로 배포가 되면 pip inistall을 통해서 모두가 설치할 수 있게 됩니다. 배포를 위해서는 우선 Pypi 계정이 필요합니다. 사이트에 접속하시고 우측 상단의 Register 버튼을 클릭해 회원가입을 진행합니다.

5. OpenID Connect를 위해 프로젝트 등록

저희는 Github Actions를 통해서 배포를 자동화할 계획입니다. 이를 위해서는 OpenID Connect를 위한 Publisher를 등록해 주어야 합니다. OpenID Connect를 사용하지 않고 영구 토큰을 발급할 수도 있지만, OpenID Connect를 통해서 영구 토큰을 발급받지 않고도 안전하게 자동 배포를 할 수 있기 때문에 보안적으로 권장되는 방법입니다.

우측 상단의 프로필 버튼을 누르고 Account Settings ➡️ Publishing 을 눌러주세요.

이후, 아래로 스크롤 하셔서 필요한 정보를 입력해 줍니다. 여기서 workflow name은 이후 6번에서 github actions에서 등록할 파일 이름입니다.

6. Github Actions Workflow 작성

Github Actions는 Github에서 제공해 주는 CI/CD 도구입니다. 이를 활용해서 자동화된 배포 등을 쉽게 수행할 수 있습니다. 쉘을 통해서 수동으로 진행하는 각 단계를 클라우드(Github) 상에서 자동으로 수행한다고 보시면 됩니다. 우선 3번에서 생성한 본인의 프로젝트 파일에 .github/workflows 폴더를 생성하고 내부에 release.yaml 파일을 생성한 다음 아래 코드를 붙여넣기 해주세요. 👉 Github 커밋 보기

# .github/workflows/release.yaml

name: Release

on:
  push:
    branches:
      - main

jobs:
  release:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      id-token: write
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: "3.10"

      - name: Install Poetry and Packages
        run: |
          curl -sSL https://install.python-poetry.org | python3 -
          poetry install

      - name: Determine Version Change
        id: version_check
        run: |
          VERSION="v$(poetry version -s)"
          echo "Current version: $VERSION"

          LATEST_RELEASE=$(curl -s -H "Authorization: token ${{ github.token }}" \
            https://api.github.com/repos/${{ github.repository }}/releases/latest | jq -r '.tag_name')
          echo "Latest release version: $LATEST_RELEASE"

          if [ "$VERSION" != "$LATEST_RELEASE" ]; then
            echo "Version has changed."
            echo "version_changed=true" >> $GITHUB_OUTPUT
            echo "new_version=$VERSION" >> $GITHUB_OUTPUT
          else
            echo "No version change detected."
            echo "version_changed=false" >> $GITHUB_OUTPUT
          fi

      - name: Create Release
        if: steps.version_check.outputs.version_changed == 'true'
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ steps.version_check.outputs.new_version }}
          generate_release_notes: True

      - name: mint API token
        if: steps.version_check.outputs.version_changed == 'true'
        id: mint-token
        run: |
          # retrieve the ambient OIDC token
          resp=$(curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
            "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=pypi")
          oidc_token=$(jq -r '.value' <<< "${resp}")

          # exchange the OIDC token for an API token
          resp=$(curl -X POST https://pypi.org/_/oidc/mint-token -d "{\"token\": \"${oidc_token}\"}")
          api_token=$(jq -r '.token' <<< "${resp}")

          # mask the newly minted API token, so that we don't accidentally leak it
          echo "::add-mask::${api_token}"

          # see the next step in the workflow for an example of using this step output
          echo "api-token=${api_token}" >> "${GITHUB_OUTPUT}"

      - name: Build and publish to PyPI
        if: steps.version_check.outputs.version_changed == 'true'
        run: |
          poetry build
          poetry publish -u __token__ -p ${{ steps.mint-token.outputs.api-token }}

여기서는 Github Actions에 대한 자세한 설명보다는 주목할 만한 몇가지 스텝에 대해서 설명하도록 하겠습니다.

  1. Determin Version Change 단계

pyproject.toml파일의 버전이 변경되었는지를 확인하는 단계입니다. pyproject.tomlversion필드가 변경된다면 (e.g. 0.1.0 -> 0.2.0) steps.version_check.outputs.version_changed 필드가 "true"로 반환됩니다. (Thanks to '민기')

  1. Create Release 단계

1번에서 steps.version_check.outputs.version_changed"true"로 반환된다면 Github Release를 생성합니다.

  1. mint API token 단계

Pypi에서 사용할 임시 토큰을 발급하는 단계입니다. 이 단계를 통해서 Pypi에서 영구 토큰을 발급하지 않고도 단기간 유효한 임시 토큰을 통해 배포를 진행할 수 있습니다. 해당 단계를 거치면 steps.mint-token.outputs.api-token에 임시 토큰이 담기게 됩니다.

  1. Build and publish to PyPi

마지막으로 Poetry를 통해서 빌드와 배포를 수행하는 단계입니다. mint API token 단계에서 생성한 토큰을 활용하여 배포를 진행하게 됩니다.

7. Github Actions 확인하기

6번 과정을 마쳤다면 해당 변경사항을 Github에 반영해 주도록 합니다. main 브랜치에 해당 코드가 반영되었다면 Github Actions가 트리거 될 것입니다. Workflow의 진행 상황은 Github 레포지토리에서 Actions 탭을 통해 확인할 수 있습니다.

8. 배포된 라이브러리 설치 및 확인

이제 모든 과정이 완료되었습니다. 본인이 배포된 라이브러리가 설치 가능한지 확인해 봅시다.

pip install konickname

성공!!

트러블 슈팅

혹시 문제가 발생한다면 댓글로 남겨주시면 감사하겠습니다. 해당 부분을 확인하고 아래 항목을 업데이트하겠습니다 :)

1. Pypi에 등록한 정보와 Github 정보가 일치하지 않으면 Actions가 실패할 수 있습니다. 레포지토리 네임 등의 정보를 잘 입력하셨는지 확인해주세요.

2. Pypi's Troubleshooting


오늘은 파이썬 라이브러리를 만들고, 이를 poetry와 Github Actions의 도움으로 자동으로 배포하는 과정에 대해서 알아보았습니다. 여러분들께서도 직접 본인의 라이브러리를 만들어서 배포해 보시면 어떨까요? 이 포스트가 그 과정에 조금이라도 도움이 되면 좋겠습니다. 읽어주셔서 감사합니다. 🥰

참고자료

반응형