Skip to content

GitHub Actions에서 uv 사용하기

설치

GitHub Actions에서 uv를 사용하려면 공식 astral-sh/setup-uv 액션을 권장한다. 이 액션은 uv를 설치하고 PATH에 추가하며, (선택적으로) 캐시를 유지하고, uv가 지원하는 모든 플랫폼을 지원한다.

uv의 최신 버전을 설치하려면 다음과 같이 설정한다:

example.yml
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v5

특정 uv 버전을 고정하는 것이 권장되는데, 다음과 같이 설정할 수 있다:

example.yml
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v5
        with:
          # 특정 버전의 uv를 설치한다.
          version: "0.6.2"

Python 설정하기

python install 명령어로 Python을 설치할 수 있다:

example.yml
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v5

      - name: Set up Python
        run: uv python install

이 방법은 프로젝트에 지정된 Python 버전을 준수한다.

또는 공식 GitHub setup-python 액션을 사용할 수 있다. GitHub가 Python 버전을 러너와 함께 캐시하기 때문에 더 빠를 수 있다.

프로젝트에 고정된 버전을 사용하려면 python-version-file 옵션을 설정한다:

example.yml
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v5

      - name: "Set up Python"
        uses: actions/setup-python@v5
        with:
          python-version-file: ".python-version"

또는 pyproject.toml 파일을 지정해 고정 버전을 무시하고 프로젝트의 requires-python 제약 조건과 호환되는 최신 버전을 사용할 수 있다:

example.yml
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v5

      - name: "Set up Python"
        uses: actions/setup-python@v5
        with:
          python-version-file: "pyproject.toml"

여러 파이썬 버전 사용하기

매트릭스를 사용해 여러 파이썬 버전을 테스트할 때, astral-sh/setup-uv를 사용해 파이썬 버전을 설정한다. 이 방법은 pyproject.toml이나 .python-version 파일에 지정된 파이썬 버전을 덮어쓴다:

example.yml
jobs:
  build:
    name: continuous-integration
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version:
          - "3.10"
          - "3.11"
          - "3.12"

    steps:
      - uses: actions/checkout@v4

      - name: Install uv and set the python version
        uses: astral-sh/setup-uv@v5
        with:
          python-version: ${{ matrix.python-version }}

setup-uv 액션을 사용하지 않는다면, UV_PYTHON 환경 변수를 설정할 수 있다:

example.yml
jobs:
  build:
    name: continuous-integration
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version:
          - "3.10"
          - "3.11"
          - "3.12"
    env:
      UV_PYTHON: ${{ matrix.python-version }}
    steps:
      - uses: actions/checkout@v4

동기화 및 실행

uv와 Python을 설치한 후, uv sync 명령어로 프로젝트를 설치할 수 있다. 그리고 uv run 명령어로 환경 내에서 명령어를 실행할 수 있다:

example.yml
name: Example

jobs:
  uv-example:
    name: python
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install uv
        uses: astral-sh/setup-uv@v5

      - name: Install the project
        run: uv sync --all-extras --dev

      - name: Run tests
        # 예를 들어, `pytest`를 사용
        run: uv run pytest tests

Tip

UV_PROJECT_ENVIRONMENT 설정을 사용하면 가상 환경을 생성하는 대신 시스템 Python 환경에 설치할 수 있다.

캐싱

워크플로 실행 간에 uv의 캐시를 저장하면 CI 시간을 단축할 수 있다.

astral-sh/setup-uv는 캐시 지속성을 기본적으로 지원한다:

example.yml
- name: Enable caching
  uses: astral-sh/setup-uv@v5
  with:
    enable-cache: true

러너에서 커스텀 캐시 디렉토리를 사용하도록 액션을 설정할 수 있다:

example.yml
- name: Define a custom uv cache path
  uses: astral-sh/setup-uv@v5
  with:
    enable-cache: true
    cache-local-path: "/path/to/cache"

또는 lockfile이 변경될 때 캐시를 무효화할 수 있다:

example.yml
- name: Define a cache dependency glob
  uses: astral-sh/setup-uv@v5
  with:
    enable-cache: true
    cache-dependency-glob: "uv.lock"

또는 requirements 파일이 변경될 때도 캐시를 무효화할 수 있다:

example.yml
- name: Define a cache dependency glob
  uses: astral-sh/setup-uv@v5
  with:
    enable-cache: true
    cache-dependency-glob: "requirements**.txt"

astral-sh/setup-uv는 각 호스트 아키텍처와 플랫폼에 대해 별도의 캐시 키를 자동으로 사용한다.

또는 actions/cache 액션을 사용해 수동으로 캐시를 관리할 수 있다:

example.yml
jobs:
  install_job:
    env:
      # uv 캐시를 위한 고정 위치 설정
      UV_CACHE_DIR: /tmp/.uv-cache

    steps:
      # ... Python과 uv 설정 ...

      - name: Restore uv cache
        uses: actions/cache@v4
        with:
          path: /tmp/.uv-cache
          key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
          restore-keys: |
            uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
            uv-${{ runner.os }}

      # ... 패키지 설치, 테스트 실행 등 ...

      - name: Minimize uv cache
        run: uv cache prune --ci

uv cache prune --ci 명령은 캐시 크기를 줄이기 위해 사용되며, CI 환경에 최적화되어 있다. 성능에 미치는 영향은 설치되는 패키지에 따라 다르다.

Tip

uv pip을 사용한다면 캐시 키에서 uv.lock 대신 requirements.txt를 사용한다.

Note

비일시적이고 셀프 호스팅된 러너를 사용할 경우 기본 캐시 디렉토리가 무한히 커질 수 있다. 이 경우 작업 간에 캐시를 공유하는 것이 최적이 아닐 수 있다. 대신 캐시를 GitHub Workspace 내부로 이동시키고 작업이 끝나면 Post Job Hook을 사용해 제거한다.

install_job:
  env:
    # uv 캐시를 위한 상대 위치 설정
    UV_CACHE_DIR: ${{ github.workspace }}/.cache/uv

Post Job Hook을 사용하려면 셀프 호스팅된 러너에 ACTIONS_RUNNER_HOOK_JOB_STARTED 환경 변수를 아래와 같은 클린업 스크립트 경로로 설정해야 한다.

clean-uv-cache.sh
#!/usr/bin/env sh
uv cache clean

uv pip 사용하기

uv 프로젝트 인터페이스 대신 uv pip 인터페이스를 사용할 때, uv는 기본적으로 가상 환경을 요구한다. 시스템 환경에 패키지를 설치하려면 모든 uv 호출 시 --system 플래그를 사용하거나 UV_SYSTEM_PYTHON 변수를 설정한다.

UV_SYSTEM_PYTHON 변수는 다양한 범위에서 정의할 수 있다.

전체 워크플로우에 대해 적용하려면 최상위 레벨에서 정의한다:

example.yml
env:
  UV_SYSTEM_PYTHON: 1

jobs: ...

특정 작업에 대해 적용하려면 워크플로우 내에서 해당 작업에 정의한다:

example.yml
jobs:
  install_job:
    env:
      UV_SYSTEM_PYTHON: 1
    ...

특정 단계에 대해 적용하려면 작업 내 해당 단계에 정의한다:

example.yml
steps:
  - name: Install requirements
    run: uv pip install -r requirements.txt
    env:
      UV_SYSTEM_PYTHON: 1

다시 비활성화하려면 uv 호출 시 --no-system 플래그를 사용한다.