[DEVOPS-004][기초] 코드 변경마다 빌드와 테스트 자동 실행하기
페이지 정보
작성자 기술팀장 작성일 26-08-31 11:35 조회 225 댓글 0본문
[이번 수업]
CI(지속적 통합)는 코드 변경을 자주 합치고 자동 빌드·테스트로 문제를 빠르게 찾는 방식입니다. 작은 Python 코드와 테스트를 로컬에서 실행한 뒤, 같은 검사를 pull request마다 수행하는 GitHub Actions 파일을 작성합니다. 실제 저장소에는 올리지 않습니다.
[선수지식]
DEVOPS-001~003의 Git·브랜치 기초와 Python 실행 방법을 알면 됩니다. YAML은 들여쓰기로 구조를 표현하는 설정 파일 형식입니다.
[학습목표]
1. workflow, event, job, runner, step의 관계를 설명한다.
2. 로컬과 CI에서 같은 테스트 명령을 실행한다.
3. 읽기 전용 권한과 실패 차단 원칙을 적용한다.
[핵심개념]
워크플로(workflow)는 `.github/workflows`에 저장하는 자동화 전체입니다. push나 pull_request 이벤트가 시작 신호이고, job은 runner(실행 머신)에서 동작합니다. job 안의 step은 기본적으로 순서대로 실행됩니다.
빌드는 소스가 실행 가능한 상태인지 확인하는 과정입니다. Python 예제는 `compileall`로 문법과 바이트코드 생성을 확인합니다. 테스트는 결과가 요구사항과 같은지 검사합니다. 명령의 종료 코드가 0이 아니면 step과 job이 실패하여 병합 전에 문제를 보여줍니다. 같은 명령을 로컬에서 먼저 실행하면 수정이 빠릅니다.
예제는 main push와 pull request에 반응합니다. `permissions: contents: read`는 자동 발급되는 `GITHUB_TOKEN`의 콘텐츠 권한을 읽기로 제한합니다. `timeout-minutes`는 멈춘 작업을 종료합니다.
[따라하기]
연습 폴더에 calculator.py를 만듭니다.
```python
def add(left, right):
return left + right
```
`tests/test_calculator.py`를 만듭니다.
```python
import unittest
from calculator import add
class CalculatorTest(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)
if __name__ == "__main__":
unittest.main()
```
`.github/workflows/ci.yml`에는 다음을 저장합니다.
```yaml
name: python-ci
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Compile
run: python -m compileall -q .
- name: Test
run: python -m unittest discover -s tests -v
```
macOS/Linux는 `python3 -m compileall -q .`와 `python3 -m unittest discover -s tests -v`, Windows는 앞의 `python3` 대신 `py`를 사용합니다. `Ran 1 test`와 `OK`가 나오면 정상입니다. GitHub runner에서는 YAML의 `python` 명령이 실행됩니다.
[흔한 실수]
로컬과 CI 명령이 다르면 한쪽에서만 실패합니다. 테스트 이름이 `test*.py` 패턴과 다르면 발견되지 않습니다. 실패 step에 `continue-on-error`를 붙이면 성공처럼 보일 수 있습니다. Python·action 버전을 명시하지 않으면 재현성이 낮아집니다.
[보안 주의]
비밀번호와 토큰을 YAML·로그에 쓰지 마세요. 비밀은 저장소 Secrets에 보관하고 필요한 job에만 전달합니다. `GITHUB_TOKEN` 권한은 최소화하세요. 외부 action은 출처를 검토하고 운영에서는 전체 commit SHA 고정을 고려합니다. 신뢰하지 않는 PR 코드를 비밀이 있는 `pull_request_target`이나 사내 self-hosted runner에서 실행하지 마세요.
[직접 해볼 과제]
1. `subtract` 함수와 테스트를 추가해 총 2개 테스트를 통과시키세요.
2. 예상값을 일부러 6으로 바꿔 실패를 확인한 뒤 복구하세요.
3. Python 3.12와 3.13 matrix를 적용할 위치를 찾아보세요.
[확인문제]
1. workflow를 시작시키는 저장소 활동을 무엇이라고 하나요?
2. 테스트 명령이 종료 코드 1을 반환하면 job은 어떻게 되나요?
3. `permissions: contents: read`를 명시하는 이유는 무엇인가요?
[다음 학습]
다음 순환은 SEC-004 입력 검증과 SQL 인젝션 방어입니다. DevOps 트랙은 DEVOPS-005 아티팩트와 캐시 관리로 이어집니다.
[공식 참고 자료]
https://docs.github.com/en/actions/get-started/understand-github-actions
https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax
https://docs.github.com/en/actions/tutorials/build-and-test-code/python
https://docs.github.com/en/actions/reference/security/secure-use
https://docs.python.org/3/library/unittest.html
CI(지속적 통합)는 코드 변경을 자주 합치고 자동 빌드·테스트로 문제를 빠르게 찾는 방식입니다. 작은 Python 코드와 테스트를 로컬에서 실행한 뒤, 같은 검사를 pull request마다 수행하는 GitHub Actions 파일을 작성합니다. 실제 저장소에는 올리지 않습니다.
[선수지식]
DEVOPS-001~003의 Git·브랜치 기초와 Python 실행 방법을 알면 됩니다. YAML은 들여쓰기로 구조를 표현하는 설정 파일 형식입니다.
[학습목표]
1. workflow, event, job, runner, step의 관계를 설명한다.
2. 로컬과 CI에서 같은 테스트 명령을 실행한다.
3. 읽기 전용 권한과 실패 차단 원칙을 적용한다.
[핵심개념]
워크플로(workflow)는 `.github/workflows`에 저장하는 자동화 전체입니다. push나 pull_request 이벤트가 시작 신호이고, job은 runner(실행 머신)에서 동작합니다. job 안의 step은 기본적으로 순서대로 실행됩니다.
빌드는 소스가 실행 가능한 상태인지 확인하는 과정입니다. Python 예제는 `compileall`로 문법과 바이트코드 생성을 확인합니다. 테스트는 결과가 요구사항과 같은지 검사합니다. 명령의 종료 코드가 0이 아니면 step과 job이 실패하여 병합 전에 문제를 보여줍니다. 같은 명령을 로컬에서 먼저 실행하면 수정이 빠릅니다.
예제는 main push와 pull request에 반응합니다. `permissions: contents: read`는 자동 발급되는 `GITHUB_TOKEN`의 콘텐츠 권한을 읽기로 제한합니다. `timeout-minutes`는 멈춘 작업을 종료합니다.
[따라하기]
연습 폴더에 calculator.py를 만듭니다.
```python
def add(left, right):
return left + right
```
`tests/test_calculator.py`를 만듭니다.
```python
import unittest
from calculator import add
class CalculatorTest(unittest.TestCase):
def test_add(self):
self.assertEqual(add(2, 3), 5)
if __name__ == "__main__":
unittest.main()
```
`.github/workflows/ci.yml`에는 다음을 저장합니다.
```yaml
name: python-ci
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Compile
run: python -m compileall -q .
- name: Test
run: python -m unittest discover -s tests -v
```
macOS/Linux는 `python3 -m compileall -q .`와 `python3 -m unittest discover -s tests -v`, Windows는 앞의 `python3` 대신 `py`를 사용합니다. `Ran 1 test`와 `OK`가 나오면 정상입니다. GitHub runner에서는 YAML의 `python` 명령이 실행됩니다.
[흔한 실수]
로컬과 CI 명령이 다르면 한쪽에서만 실패합니다. 테스트 이름이 `test*.py` 패턴과 다르면 발견되지 않습니다. 실패 step에 `continue-on-error`를 붙이면 성공처럼 보일 수 있습니다. Python·action 버전을 명시하지 않으면 재현성이 낮아집니다.
[보안 주의]
비밀번호와 토큰을 YAML·로그에 쓰지 마세요. 비밀은 저장소 Secrets에 보관하고 필요한 job에만 전달합니다. `GITHUB_TOKEN` 권한은 최소화하세요. 외부 action은 출처를 검토하고 운영에서는 전체 commit SHA 고정을 고려합니다. 신뢰하지 않는 PR 코드를 비밀이 있는 `pull_request_target`이나 사내 self-hosted runner에서 실행하지 마세요.
[직접 해볼 과제]
1. `subtract` 함수와 테스트를 추가해 총 2개 테스트를 통과시키세요.
2. 예상값을 일부러 6으로 바꿔 실패를 확인한 뒤 복구하세요.
3. Python 3.12와 3.13 matrix를 적용할 위치를 찾아보세요.
[확인문제]
1. workflow를 시작시키는 저장소 활동을 무엇이라고 하나요?
2. 테스트 명령이 종료 코드 1을 반환하면 job은 어떻게 되나요?
3. `permissions: contents: read`를 명시하는 이유는 무엇인가요?
[다음 학습]
다음 순환은 SEC-004 입력 검증과 SQL 인젝션 방어입니다. DevOps 트랙은 DEVOPS-005 아티팩트와 캐시 관리로 이어집니다.
[공식 참고 자료]
https://docs.github.com/en/actions/get-started/understand-github-actions
https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax
https://docs.github.com/en/actions/tutorials/build-and-test-code/python
https://docs.github.com/en/actions/reference/security/secure-use
https://docs.python.org/3/library/unittest.html
댓글목록 0
등록된 댓글이 없습니다.
