oto/README.md

299 lines
8.2 KiB
Markdown

# OTO CLI
YAML로 정의된 CI/CD 파이프라인을 실행하는 Dart 기반 자동화 도구.
Jenkins, FTP, Git, Slack/Mattermost, iOS/Flutter/Android 빌드 등 다양한 작업을 커맨드로 추상화하고, 파이프라인 엔진이 순차 실행한다.
---
## 설치
```bash
dart pub get
dart compile exe bin/main.dart -o oto
```
---
## 실행 모드
| 플래그 | 모드 | 설명 |
|--------|------|------|
| `-j` | `jenkins` | Jenkins 환경 변수에서 워크스페이스·YAML 읽기 |
| `-t` | `test` | 하드코딩된 테스트 데이터로 로컬 실행 |
| `-f <path>` | `file` | 지정한 YAML 파일 경로에서 파이프라인 실행 |
| (daemon) | `scheduler` | 스케줄러 데몬 모드 |
```bash
oto -j # Jenkins CI 모드
oto -t # 로컬 테스트 모드
oto -f ./build.yaml # 파일 기반 실행
```
---
## 실행 흐름
```
bin/main.dart
└── Application (singleton)
└── DataComposer ← YAML + Jenkins env 파싱
└── Pipeline
└── Command.byType(CommandType) → execute(DataCommand)
```
---
## YAML 파이프라인 구조
```yaml
property:
workspace: /path/to/project
version: 1.0.0
env: prod
commands:
- command: BuildiOS
id: buildApp
param:
workspacePath: <!property.workspace>/ios/Runner.xcworkspace
scheme: Runner
pipeline:
id: main
workflow:
- exe: buildApp
```
### 태그 시스템
| 태그 | 방향 | 설명 |
|------|------|------|
| `<!property.key>` | 읽기 | property에서 값 치환 |
| `<@property.key>` | 쓰기 | 커맨드 결과를 property에 저장 |
- 태그가 문자열 전체이면 원본 타입(List, Map 등) 유지
- 태그가 문자열 일부이면 `toString()` 변환
- 중첩 접근 지원: `<!property.build.version>`
---
## 파이프라인 흐름 제어
### exe — 단순 실행
```yaml
- exe: buildApp
```
### exe-handle — 성공/실패 분기
```yaml
- exe-handle:
id: uploadArtifact
on-success:
- exe: notifySuccess
on-fail:
- exe: notifyError
```
### if — 조건 분기
```yaml
- if:
condition-string: "<!property.env> == prod"
on-true:
- exe: deployProd
on-false:
- exe: deployDev
```
**지원 연산자:** `==`, `!=`, `<`, `<=`, `>`, `>=`
**지원 타입:** `string`, `int`, `float`, `bool`, `date`, `version`, `object`
### foreach — 반복
```yaml
- foreach:
iterator: <!property.platforms> # List 또는 Map
setValue: <@property.target>
on-do:
- exe: buildTarget
```
### while — 조건 루프
```yaml
- while:
condition-int: <!property.retry> < 3
on-do:
- exe: checkStatus
```
### switch — 멀티 케이스
```yaml
- switch:
condition-string: <!property.env>
cases:
- value: prod
tasks:
- exe: deployProd
- value: dev
tasks:
- exe: deployDev
```
### wait-until — 대기
```yaml
- async: buildStep
- wait-until-string: <!state.buildStep> != complete
```
### async — 비동기 실행
```yaml
- async: notifyStart # 완료를 기다리지 않고 다음 단계 진행
```
---
## 커맨드 카탈로그
등록된 커맨드는 `Command.specs``Command.catalogRows`가 단일 진실 소스다.
샘플은 `assets/yaml/sample/**`에서 확인한다.
---
## 데이터 모델 구조
모든 커맨드 파라미터는 `DataParam`을 상속한다.
```dart
DataParam
├── workspace?: String // 기본 작업 디렉토리
├── passExitCodes?: List<int> // 성공으로 간주할 exit code
├── setResult?: String // 결과 저장 태그
├── setExitCode?: String // exit code 저장 태그
└── showPrint?: bool
// 예시
DataBuildiOS extends DataParam {
xcodeProjectFilePath?: String
xcworkspaceFilePath?: String
scheme: String
configuration?: String
...
}
```
**워크스페이스 해석 우선순위:**
1. `param.workspace`
2. `property.workspace`
3. `DataCommon.workspace` (Jenkins env)
---
## 새 커맨드 추가
```
1. lib/oto/data/*.dart DataParam 상속 모델 정의 + @JsonSerializable
2. lib/oto/commands/command.dart CommandType enum에 값 추가
3. lib/oto/commands/{category}/ Command 상속 클래스 구현
4. Command.register(..., spec: CommandSpec(type: ..., category: ..., dataModel: ..., samplePath: ...))에 구현체 등록
5. lib/oto/commands/command_registry.dart registerAllCommands()에 등록 함수 연결
6. dart run build_runner build *.g.dart 생성
등록된 커맨드 목록: Command.catalogRows (category별 정렬)
```
---
## 스케줄러
```bash
oto scheduler -r build.yaml # 스케줄러 등록
oto scheduler -l # 목록 조회
oto scheduler -e <alias> true # 활성화/비활성화
oto scheduler -u <alias> # 해제
```
**YAML 스케줄러 설정:**
```yaml
scheduler:
alias: nightly-build
cron: "0 2 * * *" # cron 표현식 또는
# interval: 3600 # 초 단위 interval
enableLog: true
```
**플랫폼별 실행 메커니즘:**
- **Linux:** cron
- **macOS:** LaunchAgent
- **Windows:** Task Scheduler
---
## Roadmap
OTO의 장기 방향은 Jenkins 안에서 실행되는 CLI에 머물지 않고, Edge에 직접 붙는 가벼운 build/deploy agent까지 확장하는 것이다.
### Phase 1. CLI 자동화 표면 정리
- 기존 `-j`, `-f`, `scheduler` 모드는 유지한다.
- YAML 파이프라인, 커맨드 확장, 단일 바이너리 배포 구조를 OTO의 핵심 경계로 유지한다.
- 외부 자동화가 다루기 쉽도록 command catalog, YAML validation, 실행 결과, step event를 구조화된 출력으로 정리한다.
- Jenkins는 OTO를 실행하는 호환 경로로 남기되, OTO의 장기 제어면은 Jenkins 전용 환경 변수에 종속시키지 않는다.
### Phase 2. Edge bootstrap 기반 `oto-agent`
- Edge에서 먼저 OTO agent를 생성하고, 대상 머신에서 실행할 bootstrap command를 발급하는 Jenkins node 연결식 UX를 목표로 한다.
- 대상 머신은 bootstrap command 실행만으로 OS/arch에 맞는 OTO 바이너리를 설치하고 agent 설정을 생성한다.
- 폐쇄망과 개발망을 고려해 HTTPS를 기본 권장하되, HTTP local/insecure 모드도 명시적으로 지원한다.
- TLS를 강제하지 않는 환경에서는 one-time bootstrap token, Edge fingerprint 또는 public key pinning, 바이너리 checksum/signature 검증을 agent 등록 계약에 포함한다.
- 설치 후 `oto-agent``iop-node`를 거치지 않고 Edge에 직접 outbound 연결한다.
### Phase 3. 메시지 기반 빌드 에이전트
- `oto agent` 또는 `oto daemon` 모드에서 Edge와 proto-socket 기반 양방향 메시지 통신을 사용한다.
- OTO는 Edge 입장에서 build/deploy 전용 domain agent이며, generic node의 하위 실행물이 아니다.
- 기본 메시지 범위는 agent register, capabilities, run request, step event, log stream, artifact event, cancel, status, self-update를 우선한다.
- YAML 파이프라인과 커맨드 확장 모델은 그대로 유지하고, agent 모드는 이를 원격 제어 가능한 실행 표면으로 노출한다.
---
## 프로젝트 구조
```
lib/
├── cli/ # CLI 인자 파싱, 스케줄러 관리
└── oto/
├── application.dart # 싱글턴 오케스트레이터
├── commands/ # 커맨드 구현체 (카테고리별)
├── core/ # 태그 시스템, 데이터 합성, 정의 데이터
├── data/ # JSON 직렬화 데이터 모델 (*.g.dart 포함)
├── pipeline/ # 파이프라인 흐름 제어 엔진
└── utils/ # 공통 유틸리티
```
---
## 기술 스택
- **언어:** Dart (SDK >=2.18.6 <4.0.0)
- **의존성:** dart_framework (커스텀), http, json_annotation, cron, xml
- **코드 생성:** json_serializable + build_runner
```bash
dart run build_runner build # 데이터 모델 생성
```
---
## 에러 처리
- `Application.build()` `catch (e, stacktrace)` Exception과 Error 모두 처리
- 실패 `BuildResult.failure(..., exitCode: 10)` 반환하고 CLI가 부모 프로세스에 exit code 전달
- `passExitCodes` 성공으로 간주할 exit code 지정 가능