oto/apps/runner
2026-06-21 05:12:43 +09:00
..
assets feat: runner proto socket transport hardening and related updates 2026-06-20 18:23:30 +09:00
bin feat: update agent bootstrap scripts and CLI commands, move contract docs to archive 2026-06-16 07:50:31 +09:00
lib feat: runner proto-socket transport hardening - compatibility fallback and test updates 2026-06-21 04:49:43 +09:00
test archive: move 05+02,03,04_socket_smoke artifacts to archive and update smoke tests 2026-06-21 05:12:43 +09:00
analysis_options.yaml
pubspec.lock chore(workspace): 패키지 메타데이터를 정리한다 2026-06-10 08:06:09 +09:00
pubspec.yaml chore(workspace): 패키지 메타데이터를 정리한다 2026-06-10 08:06:09 +09:00
README.md feat(runner): output port 경계 작업을 반영한다 2026-06-07 13:12:46 +09:00

OTO CLI

YAML로 정의된 CI/CD 파이프라인을 실행하는 Dart 기반 자동화 도구. Jenkins, FTP, Git, Slack/Mattermost, iOS/Flutter/Android 빌드 등 다양한 작업을 커맨드로 추상화하고, 파이프라인 엔진이 순차 실행한다.


현재 상태

OTO CLI는 현재 Jenkins 실행, 로컬 YAML 파일 실행, 스케줄러 실행을 지원한다. 이 실행 표면은 이후 구조화 출력, YAML validation, 독립 Control Plane agent 확장을 추가할 때도 깨지면 안 되는 호환 기준선이다. 상세 진행 상황과 다음 작업 후보는 agent-roadmap/current.mdagent-roadmap/ROADMAP.md에서 확인한다.


설치

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      # 파일 기반 실행

CLI 호환 기준선

표면 호환 기준
oto -j Jenkins 환경 변수와 Jenkins용 YAML 탐색을 사용하는 기존 CI 실행 경로로 유지한다. Jenkins 지원을 제거하지 않는다.
oto -f <path> 지정한 YAML 파일을 Jenkins 없이 실행하는 로컬/외부 자동화 진입점으로 유지한다.
oto scheduler ... YAML을 등록하고 백그라운드 스케줄러가 실행하는 daemon 경로를 유지한다. -r, -l, -e, -u 명령 형태를 호환 표면으로 본다.
YAML 파이프라인 property, commands, pipeline.workflow 구조를 핵심 입력 계약으로 유지한다.
커맨드 확장 DataParam 모델, CommandType, Command.register(...), Command.specs/Command.catalogRows, 샘플 YAML을 커맨드 확장 경계로 유지한다.
단일 바이너리 dart compile exe bin/main.dart -o oto로 만드는 단일 실행 파일을 설치와 배포의 기본 산출물로 유지한다.

Jenkins 의존은 jenkins 실행 모드의 호환 경로로 남긴다. 새 자동화 표면은 filescheduler 모드가 Jenkins 환경 변수 없이 동작할 수 있다는 전제를 깨지 않아야 한다.

Jenkins 호환 경계

  • oto -j만 Jenkins 환경 변수와 Jenkins BuildData 입력을 읽는 compatibility adapter다.
  • oto -f <path>는 YAML 파일만 입력으로 삼으며 Jenkins env 없이 local workspace 기본값으로 실행된다.
  • oto scheduler ...는 등록된 YAML과 scheduler 설정으로 실행되며 Jenkins env를 요구하지 않는다.
  • JenkinsParameterModify는 Jenkins job XML을 다루는 command일 뿐 -j 실행 모드를 요구한다는 뜻이 아니다.

실행 흐름

bin/main.dart
  └── Application (singleton)
        └── DataComposer      ← 실행 모드별 YAML/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:
      xcworkspaceFilePath: <!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 — 단순 실행

- exe: buildApp

exe-handle — 성공/실패 분기

- exe-handle:
    id: uploadArtifact
    on-success:
      - exe: notifySuccess
    on-fail:
      - exe: notifyError

if — 조건 분기

- if:
    condition-string: "<!property.env> == prod"
    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-int: <!property.retry> < 3
    on-do:
      - exe: checkStatus

switch — 멀티 케이스

- switch:
    condition-string: <!property.env>
    cases:
    - value: prod
      tasks:
      - exe: deployProd
    - value: dev
      tasks:
      - exe: deployDev

wait-until — 대기

- async: buildStep
- wait-until-string: <!state.buildStep> != complete

async — 비동기 실행

- async: notifyStart    # 완료를 기다리지 않고 다음 단계 진행

커맨드 카탈로그

등록된 커맨드는 Command.specsCommand.catalogRows가 단일 진실 소스다. 샘플은 assets/yaml/sample/**에서 확인한다.

CLI 조회 경로

CLI 명령을 통해 등록된 커맨드 정보와 카탈로그를 직접 조회할 수 있다.

# 사람용 테이블 형식 출력
oto catalog
oto catalog --category build
oto catalog --command Print

# 자동화 및 AI 연동용 구조화된 JSON 출력 (stdout 실행 로그가 억제됨)
oto catalog --json
oto catalog --command BuildiOS --json

데이터 모델 구조

모든 커맨드 파라미터는 DataParam을 상속한다.

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별 정렬)

스케줄러

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: 3600000      # 밀리초 단위 interval
  enableLog: true

플랫폼별 실행 메커니즘:

  • Linux: cron
  • macOS: LaunchAgent
  • Windows: Task Scheduler

로드맵

상세 로드맵은 agent-roadmap/ROADMAP.md에 둔다. README에는 장기 방향과 작업 진입 문서 경로만 유지한다.

OTO의 장기 방향은 Jenkins 안에서 실행되는 CLI에 머물지 않고, OTO Control Plane에 등록되는 가벼운 build/deploy agent까지 확장하는 것이다.

  • 현재 활성 Milestone 후보는 agent-roadmap/current.md에서 확인한다.
  • CLI 자동화 표면 정리: 기존 CLI 실행 모드와 YAML 파이프라인, 커맨드 확장, 단일 바이너리 배포 구조를 장기 호환 표면으로 정리한다.
  • 독립 Control Plane 기반 oto-agent: Jenkins node 연결식 UX를 OTO Server bootstrap 기반 oto-agent 설치와 등록 계약으로 재해석한다.
  • 메시지 기반 빌드 에이전트: OTO Server가 OTO 파이프라인을 원격 제어할 수 있게 한다.

Agent bootstrap 환경 기준

  • OTO_RUNNER_RELEASE_BASE_URL은 runner binary asset을 내려받는 release source of truth다.
  • Core가 HTTP로 실행될 때는 release base URL을 자동 추론하지 않으며, 환경 변수로 주입한 값도 https:// scheme이어야 한다.
  • bootstrap command 예시는 public validation 기준만 문서화하고, enrollment token, private release host, credential 원문은 tracked 문서에 남기지 않는다.
  • bootstrap script의 --edge-url 인자는 기존 호출 호환 alias로만 보며, 새 문서와 smoke 기준은 --server-url을 사용한다.

프로젝트 구조

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
dart run build_runner build      # 데이터 모델 생성
dart test                        # 테스트 실행

에러 처리

  • Application.build()catch (e, stacktrace)로 Exception과 Error 모두 처리
  • 실패 시 BuildResult.failure(..., exitCode: 10)을 반환하고 CLI가 부모 프로세스에 exit code 전달
  • passExitCodes로 성공으로 간주할 exit code 지정 가능