OTO CLI
YAML로 정의된 CI/CD 파이프라인을 실행하는 Dart 기반 자동화 도구.
Jenkins, FTP, Git, Slack/Mattermost, iOS/Flutter/Android 빌드 등 다양한 작업을 커맨드로 추상화하고, 파이프라인 엔진이 순차 실행한다.
설치
dart pub get
dart compile exe bin/main.dart -o oto
실행 모드
| 플래그 |
모드 |
설명 |
-j |
jenkins |
Jenkins 환경 변수에서 워크스페이스·YAML 읽기 |
-t |
test |
하드코딩된 테스트 데이터로 로컬 실행 |
-f <path> |
file |
지정한 YAML 파일 경로에서 파이프라인 실행 |
| (daemon) |
scheduler |
스케줄러 데몬 모드 |
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 파이프라인 구조
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:
workflow:
- exe: buildApp
태그 시스템
| 태그 |
방향 |
설명 |
<!property.key> |
읽기 |
property에서 값 치환 |
<@property.key> |
쓰기 |
커맨드 결과를 property에 저장 |
- 태그가 문자열 전체이면 원본 타입(List, Map 등) 유지
- 태그가 문자열 일부이면
toString() 변환
- 중첩 접근 지원:
<!property.build.version>
파이프라인 흐름 제어
exe — 단순 실행
- exe: buildApp
exe-handle — 성공/실패 분기
- exe-handle:
id: uploadArtifact
on-success:
- exe: notifySuccess
on-fail:
- exe: notifyError
if — 조건 분기
- if:
condition-string: "<!property.env> == prod"
type: string
on-true:
- exe: deployProd
on-false:
- exe: deployDev
지원 연산자: ==, !=, <, <=, >, >=
지원 타입: string, int, float, bool, date, version, object
foreach — 반복
- foreach:
iterator: <!property.platforms> # List 또는 Map
setValue: <@property.target>
on-do:
- exe: buildTarget
while — 조건 루프
- while:
condition-string: "<!property.retry> < 3"
type: int
on-do:
- exe: checkStatus
switch — 멀티 케이스
- switch:
value: <!property.env>
cases:
prod:
- exe: deployProd
dev:
- exe: deployDev
wait-until — 대기
- wait-until-true:
condition-string: "<!state.buildStep> == complete"
interval: 10
async — 비동기 실행
- async: notifyStart # 완료를 기다리지 않고 다음 단계 진행
커맨드 목록
빌드
| 커맨드 |
설명 |
BuildiOS |
xcodebuild로 iOS 앱 빌드 |
ArchiveiOS |
xcodebuild archive |
ExportiOS |
xcodebuild -exportArchive |
PublishiOS |
App Store Connect 배포 |
TestflightUpload |
TestFlight 업로드 |
TestflightStatusCheck |
TestFlight 처리 상태 확인 |
TestflightDistribute |
TestFlight 그룹 배포 |
BuildFlutter |
flutter build |
BuildDart |
dart build |
BuildDartCompile |
dart compile |
BuildMSBuild |
MSBuild (.NET) |
ProductBuild |
macOS productbuild |
Notarize |
macOS 공증 |
파일
| 커맨드 |
설명 |
Copy |
파일/디렉토리 복사 (이동 포함) |
Delete |
파일/디렉토리 삭제 |
Rename |
이름 변경 |
FileRead |
파일 읽기 → property 저장 |
FileWrite |
property 값 → 파일 쓰기 |
Files |
파일 목록 조회 |
FileInfo |
파일 메타데이터 조회 |
DirectoryCreate |
디렉토리 생성 |
Zip |
압축/해제 |
Git
| 커맨드 |
설명 |
Git |
임의 git 명령 실행 |
GitCommit |
변경사항 커밋 |
GitPull |
pull |
GitPush |
push |
GitCheckout |
브랜치/파일 체크아웃 |
GitRev |
리비전 해시 조회 |
GitCount |
커밋 수 조회 |
GitReset |
reset |
GitStashPush / GitStashApply |
stash 관리 |
GitBranch |
브랜치 목록/생성/삭제 |
GitHub |
GitHub API 호출 |
GitHubPullRequestCreate / List / Close |
PR 관리 |
알림
| 커맨드 |
설명 |
Slack |
Slack 메시지 전송 |
SlackFile |
Slack 파일 업로드 |
SlackBuild |
빌드 결과 Slack 리포트 |
Mattermost |
Mattermost 메시지 전송 |
MattermostBuild |
빌드 결과 Mattermost 리포트 |
네트워크 / FTP
| 커맨드 |
설명 |
Upload |
FTP 업로드 |
Download |
FTP 다운로드 |
WebRequest |
HTTP 요청 |
WebFile |
HTTP 파일 다운로드 |
URLInfo |
URL 정보 파싱 |
문자열 / 유틸
| 커맨드 |
설명 |
Print |
메시지 출력 |
SetValue |
property 값 직접 설정 |
Delay |
지연 (초) |
Timer |
경과 시간 측정 |
StringSub |
문자열 자르기 |
StringReplace |
문자열 치환 |
StringReplacePattern |
정규식 치환 |
StringIndex |
인덱스 검색 |
JsonReader |
JSON 값 읽기 |
JsonReaderFile |
JSON 파일 읽기 |
JsonWriterFile |
JSON 파일 쓰기 |
셸 / 프로세스
| 커맨드 |
설명 |
Shell |
셸 명령 실행 |
ShellFile |
셸 스크립트 파일 실행 |
ProcessRun |
프로세스 실행 |
ProcessKill |
프로세스 종료 |
ProcessPortUse |
포트 사용 여부 확인 |
외부 서비스
| 커맨드 |
설명 |
Jira |
Jira 이슈 조회/수정 |
AwsCli |
AWS CLI 명령 실행 |
Docker |
Docker 명령 실행 |
Gradle |
Gradle 빌드 실행 |
Protobuf |
protoc 컴파일 |
JenkinsParameterModify |
Jenkins 파라미터 수정 |
SMBAuth |
SMB 인증 |
데이터 모델 구조
모든 커맨드 파라미터는 DataParam을 상속한다.
DataParam
├── workspace?: String // 기본 작업 디렉토리
├── passExitCodes?: List<int> // 성공으로 간주할 exit code
├── setResult?: String // 결과 저장 태그
├── setExitCode?: String // exit code 저장 태그
└── showPrint?: bool
// 예시
DataBuildiOS extends DataParam {
workspacePath: String
scheme: String
destination: String
...
}
워크스페이스 해석 우선순위:
param.workspace
property.workspace
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. lib/oto/commands/command_registry.dart registerAllCommands()에 등록
5. dart run build_runner build *.g.dart 생성
스케줄러
oto scheduler -r build.yaml # 스케줄러 등록
oto scheduler -l # 목록 조회
oto scheduler -e <alias> true # 활성화/비활성화
oto scheduler -u <alias> # 해제
YAML 스케줄러 설정:
scheduler:
alias: nightly-build
cron: "0 2 * * *" # cron 표현식 또는
# interval: 3600 # 초 단위 interval
enableLog: true
플랫폼별 실행 메커니즘:
- Linux: cron
- macOS: LaunchAgent
- Windows: Task Scheduler
프로젝트 구조
lib/
├── cli/ # CLI 인자 파싱, 스케줄러 관리
├── framework/ # 플랫폼 추상화, ProcessExecutor, 로깅
└── 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
dart run build_runner build # 데이터 모델 생성
에러 처리
Application.build()는 catch (e, stacktrace)로 Exception과 Error 모두 처리
- 실패 시
exit(10) 으로 부모 프로세스에 실패 신호 전달
passExitCodes로 성공으로 간주할 exit code 지정 가능