Skip to content

testors/tiny_ci

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

33 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

tiny_ci

모바일/데스크톱 앱 프로젝트의 자동 빌드 & HTTP 서빙 인프라. git commit 시 자동으로 빌드하고, 웹 UI에서 아티팩트를 다운로드할 수 있다. (기본 포트: 8888)

  • 플랫폼 무관: Android(Gradle), Flutter, iOS(fastlane), macOS 등 buildCommand에 뭐든 지정 가능
  • 최소 설정: 프로젝트 루트에 .tiny_ci.json 하나 + register.sh 한 번 실행
  • 웹 UI: 빌드 상태, 히스토리, 실시간 로그, 수동 빌드 버튼, 아티팩트 다운로드

설치

사전 준비

# Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Java 17 (Android/Gradle 빌드에 필요)
brew install openjdk@17

# Flutter SDK (Flutter 프로젝트만 해당)
brew install --cask flutter

Python 3는 macOS에 기본 포함되어 있어 별도 설치 불필요.

설치 (3단계)

# 1. tiny_ci 클론 (원하는 경로에)
git clone <repo-url> /path/to/tiny_ci

# 2. 초기 설정 (디렉토리 생성 + LaunchAgent 등록)
/path/to/tiny_ci/install.sh           # 기본 포트 8888
/path/to/tiny_ci/install.sh --port 9000  # 포트 변경 시

# 3. 앱 저장소 등록
cd /path/to/my-app
/path/to/tiny_ci/scripts/register.sh

완료. 이후 git commit 하면 자동 빌드 → http://localhost:<PORT> 에서 확인.

install.sh 는 이미 등록된 프로젝트들의 git hook도 최신 방식으로 다시 동기화한다. 또한 기존 projects/*.jsonsourceRepoPath / branch 가 없으면 현재 설정을 기준으로 자동 보정한다.

참고: register.sh는 실행 시점의 tiny_ci 경로를 git hook에 기록합니다. tiny_ci를 다른 경로로 이동한 경우 각 프로젝트에서 register.sh를 다시 실행하세요.

빌드 방식

  • tiny_ci는 개발 중인 워킹카피를 직접 빌드하지 않는다.
  • 등록된 각 프로젝트마다 tiny_ci/workspaces/<project-id>/ 에 전용 clone/workspace를 두고 여기서 빌드한다.
  • 프로젝트 JSON의 branch 에 지정된 브랜치만 fetch/checkout 해서 빌드한다.
  • git hook도 pinned branch와 현재 커밋 브랜치가 다르면 자동 빌드를 건너뛴다.
  • 반면 watchArtifacts 는 개발용 원본 저장소의 로컬 빌드 산출물을 감시한다.

새 앱 프로젝트 추가

1. 프로젝트 루트에 .tiny_ci.json 추가

{
  "id": "my-app",
  "name": "My App",
  "branch": "main",
  "buildCommand": "flutter build apk --release",
  "buildWorkingDir": "platforms/flutter",
  "artifactPath": "platforms/flutter/build/app/outputs/flutter-apk/app-release.apk",
  "artifactName": "MyApp.apk"
}
필드 필수 설명
id 프로젝트 식별자 (영문 소문자, 하이픈)
name 표시 이름
branch 권장 tiny_ci가 빌드할 고정 브랜치 (main 권장)
buildCommand 빌드 명령어 (쉘에서 그대로 실행됨)
buildWorkingDir 빌드 실행 디렉토리 (저장소 루트 기준 상대경로 권장)
artifactPath 빌드 결과물 경로 (저장소 루트 기준 상대경로 권장)
artifactName 서빙될 파일명
watchArtifacts 로컬 빌드 감지 대상 목록 (아래 참고)

branch 를 생략하면 register.sh 실행 시점의 현재 브랜치가 기본값으로 저장된다. 다만 실수로 feature branch를 서빙하지 않으려면 .tiny_ci.json 에 명시하는 편이 안전하다.

2. 등록

cd /path/to/my-app
/path/to/tiny_ci/scripts/register.sh

등록되면 tiny_ci는 프로젝트의 .tiny_ci.jsonprojects/<id>.json 으로 복사하면서, 머신 로컬 정보인 sourceRepoPath 를 추가한다.


watchArtifacts — 로컬 빌드 감지

프로젝트 저장소에서 직접 빌드한 아티팩트를 웹 UI에 별도 버튼으로 노출할 수 있다.

{
  "id": "my-android-app",
  "branch": "main",
  "artifactName": "MyApp-debug.apk",
  ...
  "watchArtifacts": [
    {
      "label": "Debug",
      "path": "app/build/outputs/apk/debug/app-debug.apk",
      "file": "MyApp-debug.apk"
    },
    {
      "label": "Release",
      "path": "app/build/outputs/apk/release/app-release.apk",
      "file": "MyApp-release.apk"
    }
  ]
}
필드 설명
label 버튼 표시 이름 (Debug / Release 등)
path 원본 저장소 내 아티팩트 경로 (상대경로 가능)
file serve 디렉토리에 저장될 파일명

표시 규칙

버튼 표시 조건 배지
Download Stable status=ready이면 항상
{label} Latest fileartifactName과 다른 경우 파일이 존재하면 항상 최신 빌드면 Latest
{label} Latest fileartifactName과 같은 경우 (tiny_ci도 빌드) 로컬이 더 최신일 때만

등록 후 /api/scan/{id} 호출 시 원본 저장소 파일과 마지막 tiny_ci 빌드를 비교해 자동 감지·복사한다.


플랫폼별 예시

Android (Gradle)

{
  "id": "my-android",
  "name": "My Android App",
  "branch": "main",
  "buildCommand": "./gradlew assembleDebug",
  "buildWorkingDir": ".",
  "artifactPath": "app/build/outputs/apk/debug/app-debug.apk",
  "artifactName": "MyApp-debug.apk"
}

Release 빌드도 배포하려면 debug keystore로 서명 설정 권장:

// app/build.gradle.kts
buildTypes {
    release { signingConfig = signingConfigs.getByName("debug") }
}

Flutter

{
  "id": "my-flutter",
  "name": "My Flutter App",
  "branch": "main",
  "buildCommand": "flutter build apk --release",
  "buildWorkingDir": ".",
  "artifactPath": "build/app/outputs/flutter-apk/app-release.apk",
  "artifactName": "MyApp.apk"
}

Google Play Internal Testing 업로드

playUpload 설정이 enabled여도 자동 업로드는 안 된다 — git push로 들어오는 일반 빌드는 artifact만 만들고 멈춘다. Play Console로 올리려면 수동 트리거가 필요하다:

  • Web UI: 프로젝트 detail 패널의 ⬆ Release 버튼 (playUpload.enabled: true인 프로젝트에만 표시)
  • HTTP: POST /api/release/<project-id> (/api/build/...와 비슷하지만 빌드 성공 시 Play 업로드까지 진행)

내부적으로는 TINY_CI_RELEASE=1 환경 변수가 build.sh에 전달되고, upload_to_play_if_configured()가 그 플래그가 있을 때만 동작한다.

설정 자체는 다음과 같다.

{
  "id": "my-flutter",
  "buildCommand": "flutter build apk --release --build-number \"$TINY_CI_BUILD_NUMBER\" && flutter build appbundle --release --build-number \"$TINY_CI_BUILD_NUMBER\"",
  "artifactPath": "build/app/outputs/flutter-apk/app-release.apk",
  "artifactName": "MyApp.apk",
  "playUpload": {
    "enabled": true,
    "packageName": "com.example.myapp",
    "track": "internal",
    "artifactPath": "build/app/outputs/bundle/release/app-release.aab",
    "artifactType": "aab",
    "serviceAccountJson": "/Users/testors/.config/tiny_ci/google-play/myapp-service-account.json",
    "releaseStatus": "completed",
    "changesInReviewBehavior": "ERROR_IF_IN_REVIEW"
  }
}
필드 설명
enabled true면 빌드 성공 후 업로드를 실행
packageName Android applicationId / Play Console 패키지명
track Internal Testing은 internal
artifactPath Play에 올릴 파일. 생략하면 tiny_ci의 artifactPath를 사용
artifactType auto, apk, aab 중 하나. 신규 Play 앱은 보통 AAB 사용
serviceAccountJson Google Play Developer API 권한이 있는 서비스 계정 JSON
releaseStatus 일반적으로 completed
changesInReviewBehavior 기본값은 기존 심사 중 변경을 건드리지 않는 ERROR_IF_IN_REVIEW

TINY_CI_BUILD_NUMBER는 tiny_ci가 빌드마다 Unix timestamp로 자동 제공한다. Flutter의 --build-number에 넣어 Play versionCode 중복 업로드 실패를 피한다.

최초 설정은 Play Console에서 한 번 해야 한다.

  1. Play Console에 앱을 생성하고 패키지명을 확정한다.
  2. Testing > Internal testing에서 tester email list 또는 Google Group을 등록한다.
  3. Google Cloud에서 Google Play Developer API를 enable한다.
  4. 서비스 계정을 만들고 Play Console Users and permissions에 초대한다. 최소한 testing track release를 만들 수 있는 권한이 필요하다.
  5. 서비스 계정 JSON을 serviceAccountJson 경로에 저장한다. 이 파일은 git에 커밋하지 않는다.
  6. Android release 빌드는 debug key가 아니라 Play 업로드용 release/upload key로 서명되도록 앱 프로젝트에서 설정한다.

iOS (fastlane)

{
  "id": "my-ios",
  "name": "My iOS App",
  "branch": "main",
  "buildCommand": "fastlane gym --scheme MyApp --output_directory build",
  "buildWorkingDir": ".",
  "artifactPath": "build/MyApp.ipa",
  "artifactName": "MyApp.ipa"
}

디렉토리 구조

tiny_ci/
├── scripts/
│   ├── build.sh        # 범용 빌드 스크립트 (project-id를 인자로 받음)
│   └── register.sh     # 프로젝트 등록 + git hook 설치
├── server.py           # HTTP 서버 (정적 파일 + REST API)
├── projects/           # 등록된 프로젝트 설정 (register.sh가 자동 생성)
│   └── my-app.json
├── workspaces/         # 프로젝트별 전용 clone/workspace
│   └── my-app/
├── serve/              # HTTP 서빙 루트 (기본 port 8888)
│   ├── index.html      # 웹 UI
│   ├── projects.json   # 전체 프로젝트 목록 (자동 갱신)
│   └── my-app/
│       ├── build-status.json
│       ├── build-history.json
│       ├── artifacts.json   # watchArtifacts 스캔 결과
│       ├── build.log        # 빌드 로그 (빌드 중 실시간 접근 가능)
│       └── MyApp.apk
├── logs/               # 빌드 로그 아카이브 (프로젝트별, 최근 10개 보관)
├── install.sh          # 최초 설치 (LaunchAgent 등록)
└── serve.sh            # HTTP 서버 수동 실행

REST API

메서드 경로 설명
GET /api/scan/{id} 원본 저장소 로컬 빌드 감지·복사, artifacts.json 갱신
POST /api/build/{id} 빌드 수동 트리거 (build.sh 백그라운드 실행)

관리

macOS

launchctl kickstart -k gui/$(id -u)/com.tiny_ci   # 재시작
launchctl bootout gui/$(id -u)/com.tiny_ci         # 중지

Linux

systemctl --user restart tiny_ci   # 재시작
systemctl --user stop tiny_ci      # 중지
systemctl --user status tiny_ci    # 상태 확인

공통

# 특정 프로젝트 수동 빌드
/path/to/tiny_ci/scripts/build.sh my-app

# 빌드 로그 실시간 확인
tail -f /path/to/tiny_ci/serve/my-app/build.log

# 프로젝트 설정 재등록 (tiny_ci 경로 변경 등)
cd /path/to/my-app && /path/to/tiny_ci/scripts/register.sh

About

Lightweight local CI — auto-build & serve app artifacts on git commit

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors