- Published on
python예제와 함께 Github Action 알아보기
- Authors
- Name
- 테크버킷
요약
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
과 같은 이름으로 저장해야 합니다.
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이 실행된 결과를 볼 수가 있습니다. 정상적으로 실행되었다면 ✓ 가 표시되지만 제대로 실행이 되지 않고 에러가 발생했다면 ❌로 표시됩니다. 각 리스트 항목을 클릭하면 실행에 대한 자세한 정보를 알 수 있습니다.
발전하기: 크롤링 예시
이번에는 좀더 발전하여 Github Action이 한시간에 한번식 크롤링을 수행하도록 한번 만들어보겠습니다.
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
를 작성해야 합니다.
beautifulsoup4==4.9.3
requests==2.26.0
작업 파일
먼저, 작업파일에서 update_time.py
를 recent_techbukket.py
로 수정합니다.
...
- name: Run Python script # 파이썬 코드 실행
run: |
python recent_techbukket.py
...
또한 1시간에 한번씩 작업이 수행되도록 on.schedule
을 추가합니다. 이렇게 작업을 추가하면 on.schedule
과 on.push
두 이벤트 중 하나라도 발생하면 my-job 작업이 실행됩니다.
...
on:
schedule:
- cron: '0 * * * *' # 매 시간 0분에 실행
push:
branches:
- main # 원하는 브랜치 이름
...
cron 표현식은 분, 시, 일, 월, 요일 순서로 구성됩니다. 따라서 위의 예제에서 0 * * * *
은 분은 0
, 나머지는 *
으로 지정되어 시간, 일, 월, 요일 모두에 대해 매 시간마다 실행하도록 지정합니다.
최종적으로 생성된 파일은 다음과 같습니다.
그러면 메인 브랜치에 커밋을 올릴 때마다 이렇게 html 파일이 새로 만들어집니다.
에러
Github Actions를 사용하면서 발생할 수 있는 에러 몇가지와 해결방법을 몇 가지 소개합니다.
권한 문제
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.{변수 이름}
으로 가져올 수 있습니다.
참고문서
- Configuring the default GITHUB_TOKEN permissions(Github)
- 자동 토큰 인증(Github)
- GitHub Actions / Variables(Github)
모듈 문제
ModuleNotFoundError: No module named 'requests'
Error: Process completed with exit code 1.
해결: 'requests' 모듈이 설치되어 있지 않아 발생하는 에러입니다.requirements.txt
파일이 정상적으로 있는지, 필요한 모듈이 이 파일에 잘 명시되어 있는지 확인해야 합니다.
노드 버전 문제
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)에 명시해 주어야 합니다.
(...)
jobs:
build:
(...)
steps:
(...)
- name: Use Node.js # 노드 설정
uses: actions/setup-node@v2
with:
node-version: '16'
(...)
마무리
이상으로 Github Action에서 python을 실행하는 예시를 알아보았습니다. GitHub Actions을 활용하여, 안정적이고 효율적인 프로세스를 만들어 보세요. 더 많은 내용을 알고 싶다면 깃허브 액션에 대한 Github공식 문서를 읽어보는 것도 권장드립니다.