Published on

python예제와 함께 Github Action 알아보기

Authors
  • 테크버킷
    Name
    테크버킷
    Twitter

요약

Github Action의 개념, python 코드 활용 예시, 자주 발생하는 에러를 소개합니다. Python 코드를 사용하여 크롤링을 수행하고 파일을 수정하는 예시를 통해 Github 작업(Workflow)를 좀더 잘 이해할 수 있습니다. 이 글을 이해하려면 git, github, yaml, python 에 대한 이해가 필요할 수 있습니다.

Github Action

GitHub Actions은 GitHub에서 호스팅되는 작업 자동화 플랫폼입니다. 이를 사용하면 코드 변경, 이벤트 및 일정 기간에 따라 자동으로 작업을 실행할 수 있습니다. 예를 들어, 코드 푸시, PR(Pull Request) 생성, 스케줄링 된 작업 등의 이벤트에 대해 자동으로 빌드, 테스트, 배포 등의 작업을 수행할 수 있습니다.

Workflow

GitHub Actions를 사용하려면 작업(Workflow)이 정의되어야 합니다. Workflow 파일에는 어떤 작업이 어떻게 수행될지를 정의하니다.

Workflow는 YAML 파일 형식으로 작성하여 .github/workflows 폴더에 저장되어야 합니다. 파일 이름은 자유롭게 지정할 수 있지만 .yml 또는 .yaml 확장자를 사용하여 저장하면 됩니다.

예시

파이썬 코드를 실행하여 index.html 파일에 업데이트된 시간을 표시하는 예시를 알아보겠습니다.

파이썬 코드 작성

아래는 index.html 파일에 현재 시간을 표시하는 update_time.py 파일의 예시입니다.

import datetime

# 현재 시간 구하기
now = datetime.datetime.now()
current_time = now.strftime("%Y-%m-%d %H:%M:%S")

# HTML 파일 업데이트
with open("index.html", "w") as f:
    f.write(f"Last updated at {current_time}")

이 코드는 현재 시간을 datetime 모듈을 사용하여 구하고, index.html 파일을 열어서 파일 내용을 업데이트합니다. strftime 함수를 사용하여 날짜 및 시간 형식을 지정하고, f.write 함수를 사용하여 파일에 새로운 내용을 씁니다.

이제 위 코드를 update_time.py 파일에 저장하고, 이 파일을 리포지토리 내의 루트에 저장합니다.

그 다음은 GitHub Actions에서 이 파일을 실행하도록 Workflow 파일을 작성할 것입니다.

Workflow 정의

이 파일을 GitHub 리포지토리의 .github/workflows 디렉토리에 update_test_html.yml과 같은 이름으로 저장해야 합니다.

update_test_html.yml
name: Update test.html with current time

on:
  push: # 코드가 푸시될 때마다 작업을 실행
    branches: [ main ] # main 브랜치에서만 실행

jobs:
  build:
    runs-on: ubuntu-latest # 실행할 환경 선택
    steps:
    - uses: actions/checkout@v2 # 리포지토리 체크아웃
    - name: Use Node.js # 노드 설정
      uses: actions/setup-node@v2
      with:
        node-version: '16'
    - name: Set up Python # 파이썬 설정
      uses: actions/setup-python@v2
      with:
        python-version: 3.x # 파이썬 버전 선택
    - name: Install dependencies # 의존성 설치
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
    - name: Run Python script # 파이썬 코드 실행
      run: |
        python update_time.py
    - name: Commit updated index.html # 변경된 index.html 파일 커밋
      uses: EndBug/add-and-commit@v7
      with:
        author_name: Your Name # 사용자 이름
        author_email: your_email@example.com # 사용자 이메일
        message: Update index.html with current time # 커밋 메시지
        add: "index.html" # 변경된 파일 추가
  • on은 작업을 실행할 이벤트를 정의합니다. push 이벤트는 코드가 푸시될 때마다 작업을 실행하도록 설정되어 있습니다.
  • jobs는 작업을 정의하고, build는 작업 이름입니다. runs-on은 작업을 실행할 환경을 선택합니다. 이 예제에서는 ubuntu-latest를 선택하여 리눅스 환경에서 작업을 실행하도록 설정합니다.
  • steps은 작업 내에서 수행할 단계를 정의합니다. 첫 번째 단계는 리포지토리를 체크아웃하고, 두 번째 단계에서는 파이썬을 설정합니다. 세 번째 단계에서는 필요한 의존성을 설치하고, 네 번째 단계에서는 파이썬 코드를 실행합니다. 마지막 단계에서는 변경된 test.html 파일을 커밋합니다.
  • EndBug/add-and-commit 액션을 사용하여 파일을 커밋할 수 있습니다. 이 액션은 파일을 커밋하고 푸시하는 것까지 자동으로 처리합니다.
  • name:Set up Python 의 아래에 파이썬 코드를 실행하여 index.html 파일에 업데이트된 시간을 표시하는 파이썬 코드를 실행하도록 작성되어 있습니다.

최종적으로 생성된 파일은 다음과 같습니다.

생성된 파일 구조

깃허브의 리포지토지에 접속하여, 'Actions' 탭을 클릭하면, Action이 실행된 결과를 볼 수가 있습니다. 정상적으로 실행되었다면 ✓ 가 표시되지만 제대로 실행이 되지 않고 에러가 발생했다면 ❌로 표시됩니다. 각 리스트 항목을 클릭하면 실행에 대한 자세한 정보를 알 수 있습니다.

Setting>Actions 페이지

발전하기: 크롤링 예시

이번에는 좀더 발전하여 Github Action이 한시간에 한번식 크롤링을 수행하도록 한번 만들어보겠습니다.

recent_techbukket.py

recent_techbukket.py를 작성하고, 작업 파일에서 이 파일을 실행하도록 할 것입니다.

recent_techbukket.py
import requests
from bs4 import BeautifulSoup

url = "https://techbukket.com"
response = requests.get(url)

soup = BeautifulSoup(response.content, "html.parser")

links = []
for link in soup.find_all("a"):
    if len(links) >= 5:
        break
    if link.has_attr("href"):
        href = link.get("href")
        if href.startswith("/"):
            links.append("https://techbukket.com" + href)
        else if href.startswith("http"):
            links.append(href)

with open("index.html", "w") as f:
    f.write("<h2>테크버킷의 최신 게시물</h2>\n")
    f.write("<ul>\n")
    for link in links:
        f.write(f"<li><a href='{link}'>{link}</a></li>\n")
    f.write("</ul>")

requirements.txt

앞서 소개한 예시의 update_time.py 파일을 실행하기 위해서는 별도의 모듈 설치가 필요하지 않았지만 이번에는 BeautifulSoup이라는 모듈을 사용하므로 requirements.txt에 이를 명시해야 합니다. Workflow에서도 requirements를 설치하도록 해야합니다. 아래처럼 requirements.txt를 작성해야 합니다.

requirements.txt
beautifulsoup4==4.9.3
requests==2.26.0

작업 파일

먼저, 작업파일에서 update_time.pyrecent_techbukket.py로 수정합니다.

update_test_html.yml
...
    - name: Run Python script # 파이썬 코드 실행
      run: |
        python recent_techbukket.py
...

또한 1시간에 한번씩 작업이 수행되도록 on.schedule을 추가합니다. 이렇게 작업을 추가하면 on.scheduleon.push두 이벤트 중 하나라도 발생하면 my-job 작업이 실행됩니다.

update_test_html.yml
...
on:
  schedule:
    - cron: '0 * * * *' # 매 시간 0분에 실행
  push:
    branches:
      - main # 원하는 브랜치 이름
...

cron 표현식은 분, 시, 일, 월, 요일 순서로 구성됩니다. 따라서 위의 예제에서 0 * * * *은 분은 0, 나머지는 *으로 지정되어 시간, 일, 월, 요일 모두에 대해 매 시간마다 실행하도록 지정합니다.

최종적으로 생성된 파일은 다음과 같습니다.

생성된 파일 구조

그러면 메인 브랜치에 커밋을 올릴 때마다 이렇게 html 파일이 새로 만들어집니다.

에러

Github Actions를 사용하면서 발생할 수 있는 에러 몇가지와 해결방법을 몇 가지 소개합니다.

권한 문제

Error
Error: Error: Pushing to https://github.com/xxx/github-action-test
remote: Write access to repository not granted.
fatal: unable to access 'https://github.com/xxx/github-action-test/': The requested URL returned error: 403

해결방법: 깃허브 리포지토리의 Settings에서 작업(Workflow) permissions을 "Read and Write Permission"로 설정합니다. 또는 secrets에 권한이 있는 토큰을 사용하도록 등록하고 작업(Workflow) 파일에서 github 인증을 수행하도록 수정하는 것도 가능합니다. settings > Secrets 에 secret 변수를 추가하면 작업(Workflow)에서 secret.{변수 이름}으로 가져올 수 있습니다.

참고문서

모듈 문제

Error
ModuleNotFoundError: No module named 'requests'
Error: Process completed with exit code 1.

해결: 'requests' 모듈이 설치되어 있지 않아 발생하는 에러입니다.requirements.txt 파일이 정상적으로 있는지, 필요한 모듈이 이 파일에 잘 명시되어 있는지 확인해야 합니다.

노드 버전 문제

Node.js 12 are deprecated
Error
Node.js 12 actions are deprecated. Please update the following actions to use Node.js 16: actions/checkout@v2, actions/setup-python@v2. For more information see: https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/.

해결: 에러에 나와있는 링크에 따르면 node12 버전은 더이상 사용할 수 없고 node 16을 사용해야 한다고 합니다. 이 에러를 해결하기 위해서는 노드 버전 16을 사용하도록 작업(Workflow)에 명시해 주어야 합니다.

YAML
(...)
jobs:
  build:
    (...)
    steps:
    (...)
    - name: Use Node.js # 노드 설정
      uses: actions/setup-node@v2
      with:
        node-version: '16'
    (...)

마무리

이상으로 Github Action에서 python을 실행하는 예시를 알아보았습니다. GitHub Actions을 활용하여, 안정적이고 효율적인 프로세스를 만들어 보세요. 더 많은 내용을 알고 싶다면 깃허브 액션에 대한 Github공식 문서를 읽어보는 것도 권장드립니다.