# CI (/ko/docs/cli/ci)

작업 공간은 텍스트 파일 폴더이므로 테스트 대상 API와 같은 저장소에 둘 수 있습니다. CI에서 명령줄 도구는 작업 공간을 확인하고, 요청을
검사와 함께 실행하고, CI 시스템이 보여 주는 보고서를 씁니다. 검사가 실패하면 작업이 실패합니다.

## 작업이 하는 일 [#what-a-job-does]

```sh
echolot validate Alpenglow.echolot --env staging
echolot run Alpenglow.echolot --env staging \
  --reporter console --reporter junit --out echolot-results.xml
```

1. [`echolot validate`](/docs/cli/validate)는 아무것도 보내기 전에 깨진 파일이나 빠진 변수를 잡아냅니다.
2. [`echolot run`](/docs/cli/run)은 요청을 보내고 검사와 스크립트를 실행합니다. `console`은 작업 로그에 실행 내용을 출력하고,
   `junit`은 CI가 테스트 결과로 읽는 파일을 씁니다.
3. 요청이 실패하면 종료 코드가 1이므로 작업이 실패합니다.

작업 공간의 일부만 실행하려면 `--folder`를, 데이터 기반 실행에는 `--data`를, 처음 실패에서 멈추려면 `--bail`을, 불안정한 의존성에는
`--retries`를 추가합니다.

## CI의 비밀 값 [#secrets-in-ci]

작업 공간 파일에는 비밀 값이 없으므로 CI가 제공해야 합니다. 각 값을 CI의 비밀 값에 저장하고, 변수 이름을 대문자로 한
`ECHOLOT_SECRET_<NAME>`이라는 환경 변수로 전달합니다([비밀 값](/docs/cli#secrets) 참조).

| 작업 공간의 비밀 변수 | CI의 환경 변수 |
| --- | --- |
| `password` | `ECHOLOT_SECRET_PASSWORD` |
| `token` | `ECHOLOT_SECRET_TOKEN` |
| `api-key` | `ECHOLOT_SECRET_API_KEY` |

또는 파일에 써서 `--secrets`로 전달합니다. 한 줄에 `NAME=value` 하나입니다. 그 파일은 절대 커밋하지 마십시오.

대부분의 CI 시스템은 `CI`를 설정하며 이것이 키체인을 꺼서 작업이 확인 창을 기다리는 일이 없게 합니다. 보고서는 비밀 값을 가리므로
아티팩트로 보관해도 안전합니다.

- **OAuth를 쓰는 MCP 서버:** Mac에서 `echolot mcp sign-in <server> --print`로 한 번 로그인하고, 출력된 `ECHOLOT_SECRET_…` 값을 CI의 비밀
  값으로 저장합니다. [`echolot mcp`](/docs/cli/mcp)를 참조하십시오.
- **캡처한 비밀 값:** 키체인이 없으면 비밀 변수로 캡처한 응답이 같은 실행의 다음 요청으로 이어지지 않습니다. 그런 변수에는 CI에서 값을
  주거나, 비밀 값이 아닌 변수로 캡처하십시오.

## GitHub Actions [#github-actions]

macOS 러너에서 릴리스의 도구를 내려받아 실행합니다.

```yaml
# .github/workflows/api-checks.yml
name: API checks
on: [push, pull_request]

jobs:
  echolot:
    runs-on: macos-15
    steps:
      - uses: actions/checkout@v4

      - name: Install the Echolot command-line tool
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          gh release download --repo staticdreams/echolot-public --pattern 'echolot-*-macos.zip'
          unzip -o echolot-*-macos.zip -d "$RUNNER_TEMP/echolot"
          echo "$RUNNER_TEMP/echolot" >> "$GITHUB_PATH"

      - name: Check the workspace
        run: echolot validate Alpenglow.echolot --env staging
        env:
          ECHOLOT_SECRET_PASSWORD: ${{ secrets.ALPENGLOW_STAGING_PASSWORD }}

      - name: Run the requests
        run: |
          echolot run Alpenglow.echolot --env staging \
            --reporter console --reporter junit --out echolot-results.xml
        env:
          ECHOLOT_SECRET_PASSWORD: ${{ secrets.ALPENGLOW_STAGING_PASSWORD }}

      - name: Keep the report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: echolot-results
          path: echolot-results.xml
```

태그 없이 `gh release download`를 쓰면 최신 릴리스를 받습니다. 버전을 고정하려면 태그를 지정하십시오(`gh release download v0.5.0 …`).

### Linux 러너 [#linux-runners]

도구는 현재 macOS에서 실행됩니다. 위 작업은 macOS 러너를 사용합니다. Linux 빌드, Docker 이미지, 바로 쓸 수 있는 GitHub Action은 아직
공개되지 않았으며, 공개되면 이 페이지에서 보여 드립니다.

## 다른 CI [#any-other-ci]

모든 것이 종료 코드가 있는 명령이므로 셸 명령을 실행하는 CI 시스템이라면 무엇이든 작동합니다. macOS 러너용 스크립트:

```sh
#!/bin/sh
set -e

echolot validate Alpenglow.echolot --env staging
echolot run Alpenglow.echolot --env staging \
  --reporter console \
  --reporter junit --out reports/echolot.xml \
  --reporter html --out reports/echolot.html
```

`set -e`는 실패한 첫 명령에서 스크립트를 멈춥니다. CI의 테스트 보고서 설정이 `reports/echolot.xml`을 가리키게 하고,
`reports/echolot.html`은 사람이 열어 볼 수 있도록 아티팩트로 보관하십시오.

## 추가 게이트 [#more-gates]

| 검사 | 명령 | 실패하는 경우 |
| --- | --- | --- |
| OpenAPI 명세가 건전함 | `echolot spec lint specs/alpenglow.yaml --strict` | 오류나 경고가 있습니다. |
| 요청이 명세를 따름 | `echolot spec check -w Alpenglow.echolot <folder>` | 명세가 바뀌었는데 폴더가 업데이트되지 않았습니다. |
| GraphQL 스키마가 호환성을 유지함 | `echolot graphql diff before.graphql specs/shop.graphql` | 호환되지 않는 변경이 있습니다(더 엄격하게 하려면 `--fail-on dangerous`). |
| 모델이 MCP 서버를 쓸 수 있음 | `echolot mcp check --url https://demo.echolot.dev/mcp --quality --strict` | 모델이 도구에서 혼동할 수 있습니다. |
| 플로가 여전히 작동함 | `echolot flow run morning-stock-check -w Alpenglow.echolot --no-input` | 플로나 플로의 테스트 중 하나가 실패합니다. |
| 에이전트가 일을 해낼 수 있음 | `echolot agent "…" -w Alpenglow.echolot --policy-file ci-policy.toml` | 에이전트가 끝내지 못합니다. |

API에 필요하지만 CI에 없는 서버는 먼저 [모의 서버](/docs/cli/mock)를 백그라운드에서 실행하십시오.

빈 저장소에서 시작하는 안내는 [CI에서 API 테스트](/docs/tutorials/test-in-ci)를 참조하십시오.
