feat: .env.example 파일에 CI 환경 설명 추가 및 config.py 수정

This commit is contained in:
hyeonggil
2026-03-28 10:12:13 +09:00
parent fd84a4da81
commit 1d3c4850bf
5 changed files with 163 additions and 1 deletions

View File

@@ -0,0 +1,55 @@
---
description: 커밋 메시지는 Conventional Commits + 한글 본문
alwaysApply: true
---
# 커밋 메시지 (Conventional Commits + 한글)
## 형식
- **한 줄:** `<타입>(선택 범위): <한글 설명>`
- **타입·콜론·공백 뒤 설명은 반드시 한글**로 작성한다.
- 제목은 **50자 전후**, 명령형·현재형으로 짧게 쓴다. (예: "추가함" 대신 "추가")
## 허용 타입
| 타입 | 용도 |
|------|------|
| `feat` | 새 기능 |
| `fix` | 버그 수정 |
| `docs` | 문서만 변경 |
| `style` | 포맷·세미콜론 등, 동작 변화 없음 |
| `refactor` | 리팩터링 (기능 변화 없음) |
| `test` | 테스트 추가·수정 |
| `chore` | 빌드·설정·잡일 |
| `perf` | 성능 개선 |
| `ci` | CI 설정 |
| `build` | 빌드 시스템·의존성 |
| `revert` | 되돌리기 |
## 예시
```text
feat: 로그인 실패 시 텔레그램 알림 전송
fix: GAME_COUNT 빈 문자열일 때 기본값 적용
refactor: 설정 로드 로직을 config 모듈로 분리
docs: README에 NAS 배포 절차 추가
test: LottoBuyer 로그인 성공 케이스 mock 테스트
chore: requirements.txt 버전 고정
ci: Gitea Actions에서 Secret 기반 설정 검증
```
## 범위(선택)
- 괄호로 모듈을 짧게: `feat(lotto_buyer): 세션 만료 시 재로그인 시도`
- 필요할 때만 사용.
## 본문이 필요할 때
- 제목 다음 빈 줄 뒤 **본문도 한글**로 상세 설명.
- 푸터: `BREAKING CHANGE:` 등은 프로젝트에 필요할 때만 영문 키워드 유지 가능.
## 금지
- 타입 없이 자유 문장만 쓰기
- 제목 전체를 영어만으로 쓰기 (이 프로젝트 기본은 한글 설명)

55
.cursorRules Normal file
View File

@@ -0,0 +1,55 @@
---
description: 커밋 메시지는 Conventional Commits + 한글 본문
alwaysApply: true
---
# 커밋 메시지 (Conventional Commits + 한글)
## 형식
- **한 줄:** `<타입>(선택 범위): <한글 설명>`
- **타입·콜론·공백 뒤 설명은 반드시 한글**로 작성한다.
- 제목은 **50자 전후**, 명령형·현재형으로 짧게 쓴다. (예: "추가함" 대신 "추가")
## 허용 타입
| 타입 | 용도 |
|------|------|
| `feat` | 새 기능 |
| `fix` | 버그 수정 |
| `docs` | 문서만 변경 |
| `style` | 포맷·세미콜론 등, 동작 변화 없음 |
| `refactor` | 리팩터링 (기능 변화 없음) |
| `test` | 테스트 추가·수정 |
| `chore` | 빌드·설정·잡일 |
| `perf` | 성능 개선 |
| `ci` | CI 설정 |
| `build` | 빌드 시스템·의존성 |
| `revert` | 되돌리기 |
## 예시
```text
feat: 로그인 실패 시 텔레그램 알림 전송
fix: GAME_COUNT 빈 문자열일 때 기본값 적용
refactor: 설정 로드 로직을 config 모듈로 분리
docs: README에 NAS 배포 절차 추가
test: LottoBuyer 로그인 성공 케이스 mock 테스트
chore: requirements.txt 버전 고정
ci: Gitea Actions에서 Secret 기반 설정 검증
```
## 범위(선택)
- 괄호로 모듈을 짧게: `feat(lotto_buyer): 세션 만료 시 재로그인 시도`
- 필요할 때만 사용.
## 본문이 필요할 때
- 제목 다음 빈 줄 뒤 **본문도 한글**로 상세 설명.
- 푸터: `BREAKING CHANGE:` 등은 프로젝트에 필요할 때만 영문 키워드 유지 가능.
## 금지
- 타입 없이 자유 문장만 쓰기
- 제목 전체를 영어만으로 쓰기 (이 프로젝트 기본은 한글 설명)

View File

@@ -1,3 +1,6 @@
# 로컬: 이 파일을 .env 로 복사 후 값 입력
# Gitea Actions: 동일 변수명을 리포지토리 Secret 으로 등록 (CI=true 일 때 .env 는 읽지 않음)
# 동행복권 계정 정보 (필수) # 동행복권 계정 정보 (필수)
LOTTO_USERNAME=your_dhlottery_id LOTTO_USERNAME=your_dhlottery_id
LOTTO_PASSWORD=your_dhlottery_password LOTTO_PASSWORD=your_dhlottery_password

40
.gitea/workflows/ci.yml Normal file
View File

@@ -0,0 +1,40 @@
# Gitea Actions: 리포지토리 설정 → Actions → Secrets 에 동일 이름 등록
# 로컬은 프로젝트 루트 .env, CI 는 아래 secrets.* 가 환경변수로 주입됨
name: CI
on:
push:
branches:
- main
- master
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: 의존성 설치
run: pip install -r requirements.txt
- name: 단위 테스트
env:
CI: true
run: PYTHONPATH=src python -m unittest discover -s tests -v
# PR 은 fork 등에서 Secret 이 없을 수 있어 push 일 때만 검증
- name: Secret 기반 설정 로드 검증
if: github.event_name == 'push'
env:
CI: true
LOTTO_USERNAME: ${{ secrets.LOTTO_USERNAME }}
LOTTO_PASSWORD: ${{ secrets.LOTTO_PASSWORD }}
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
run: PYTHONPATH=src python -c "from config import load_config; load_config(); print('config: OK')"

View File

@@ -12,7 +12,15 @@ class Config:
TELEGRAM_CHAT_ID: str TELEGRAM_CHAT_ID: str
def _is_ci_environment() -> bool:
v = os.environ.get("CI", "").strip().lower()
return v in ("true", "1", "yes")
def _load_dotenv_if_present() -> None: def _load_dotenv_if_present() -> None:
# Gitea Actions 등 CI: Secret으로 주입된 os.environ만 사용 (.env 미로드)
if _is_ci_environment():
return
try: try:
from dotenv import load_dotenv from dotenv import load_dotenv
@@ -25,7 +33,8 @@ def _load_dotenv_if_present() -> None:
def load_config() -> Config: def load_config() -> Config:
_load_dotenv_if_present() _load_dotenv_if_present()
game_count = int(os.environ.get("GAME_COUNT", "5")) raw_gc = os.environ.get("GAME_COUNT", "5").strip()
game_count = int(raw_gc if raw_gc else "5")
if not 1 <= game_count <= 5: if not 1 <= game_count <= 5:
raise ValueError(f"GAME_COUNT는 1~5 사이여야 합니다. 현재값: {game_count}") raise ValueError(f"GAME_COUNT는 1~5 사이여야 합니다. 현재값: {game_count}")