수정 작업과 PR
수정 작업은 피드백, 수정 지시, 완료 기준, PR URL을 함께 관리하는 기록입니다. 생성에는 work-items:write, 조회에는 work-items:read 권한이 필요합니다.
수정 작업 생성
POST /api/v1/apps/:appId/automation/change-requests
Content-Type: application/json| 필드 | 필수 | 제약 |
|---|---|---|
title | 예 | 공백 제거 후 1–160자 |
instructions | 예 | 공백 제거 후 1–10000자 |
acceptanceCriteria | 아니요 | 공백 제거 후 최대 10000자. 기본 빈 문자열 |
issueIds | 예 | 같은 앱의 피드백 UUID 1–20개. 중복 불가 |
clientRequestId | 예 | 이 생성 요청을 구분하는 UUID |
아래 예시의 피드백 ID는 실제 조회한 ID로, clientRequestId는 새 작업을 만들기 전에 생성한 UUID로 바꾸세요. 응답을 받지 못해 재시도할 때는 같은 값을 유지합니다.
curl --fail-with-body \
"$OPENTESTER_API_URL/apps/$OPENTESTER_APP_ID/automation/change-requests" \
--header "Authorization: Bearer $OPENTESTER_AGENT_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"title": "저장 직후 목록 갱신 수정",
"instructions": "저장 성공 후 목록 상태를 갱신하고 중복 추가가 없는지 확인합니다.",
"acceptanceCriteria": "새 항목이 즉시 한 번 표시되고 화면 재진입 후에도 유지됩니다.",
"issueIds": ["bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"],
"clientRequestId": "dddddddd-dddd-4ddd-8ddd-dddddddddddd"
}'응답 201 예시:
{
"changeRequest": {
"id": "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
"appId": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
"title": "저장 직후 목록 갱신 수정",
"instructions": "저장 성공 후 목록 상태를 갱신하고 중복 추가가 없는지 확인합니다.",
"acceptanceCriteria": "새 항목이 즉시 한 번 표시되고 화면 재진입 후에도 유지됩니다.",
"issueIds": ["bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"],
"status": "open",
"pullRequestUrl": null,
"createdBy": "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
"createdAt": "2026-10-28T02:00:00.000Z",
"updatedAt": "2026-10-28T02:00:00.000Z"
}
}중복 생성 방지
서버는 앱·작업 생성자·clientRequestId 조합으로 같은 요청을 식별합니다. 같은 토큰 소유자의 다른 토큰으로 재시도해도 이 기준을 적용합니다.
- 같은 ID와 같은 내용: 이미 생성한 작업을 반환합니다.
- 같은 ID와 다른 내용:
409 Conflict입니다. - 다른 ID: 같은 피드백과 같은 내용이어도 새 작업을 만듭니다.
비교할 때 앞뒤 공백을 제거하고, UUID를 소문자로 바꾸며, issueIds를 정렬합니다. 따라서 배열 순서만 달라진 재시도는 같은 요청입니다. 이 처리는 작업의 선점이나 자동 중복 병합을 제공하지 않습니다. 작업을 만들기 전에 기존 작업을 조회하세요.
목록과 상세 조회
GET /api/v1/apps/:appId/automation/change-requests?limit=20&offset=0
GET /api/v1/apps/:appId/automation/change-requests/:requestId목록은 최신 생성 순서입니다. limit은 기본 20·최대 50, offset은 기본 0·최대 100000입니다. 상태 필터는 제공하지 않습니다.
목록의 200 응답은 다음 구조이며 각 항목은 생성 응답의 changeRequest와 같은 객체입니다.
{
"changeRequests": [],
"total": 0,
"limit": 20,
"offset": 0
}export CHANGE_REQUEST_ID="cccccccc-cccc-4ccc-8ccc-cccccccccccc"
curl --fail-with-body \
"$OPENTESTER_API_URL/apps/$OPENTESTER_APP_ID/automation/change-requests/$CHANGE_REQUEST_ID" \
--header "Authorization: Bearer $OPENTESTER_AGENT_TOKEN"상세 200 응답은 { "changeRequest": { ... } }입니다. 대상 앱에서 찾을 수 없는 작업은 404입니다.
PR 연결
코딩 도구에서 수정과 테스트를 마친 뒤 생성한 GitHub PR URL을 연결합니다. 필요한 권한은 work-items:write입니다.
POST /api/v1/apps/:appId/automation/change-requests/:requestId/pull-request
Content-Type: application/jsoncurl --fail-with-body \
"$OPENTESTER_API_URL/apps/$OPENTESTER_APP_ID/automation/change-requests/$CHANGE_REQUEST_ID/pull-request" \
--header "Authorization: Bearer $OPENTESTER_AGENT_TOKEN" \
--header "Content-Type: application/json" \
--data '{"url":"https://github.com/your-org/your-app/pull/42"}'응답 201은 { "changeRequest": { ... } }이며 status가 pr_linked, pullRequestUrl이 저장한 주소로 바뀝니다.
| 규칙 | 동작 |
|---|---|
| 허용 URL | https://github.com/{owner}/{repo}/pull/{number} |
| PR 번호 | 0으로 시작하지 않는 양의 정수, 최대 10자리 |
| URL 추가 요소 | query, fragment, 인증 정보, 포트는 허용하지 않음 |
| 정규화 | owner·repo를 소문자로 저장하고 마지막 / 제거 |
| 같은 URL 재연결 | 기존 작업 반환. 안전하게 재시도 가능 |
| 다른 URL 연결 | 409. 작업당 PR 한 개 |
현재 GitHub.com 주소만 지원합니다. GitLab이나 GitHub Enterprise의 별도 호스트는 지원하지 않습니다.
PR 연결의 의미
서버는 URL 형식을 검사해 저장합니다. 실제 PR의 존재, 저장소 접근 권한, CI 결과, 병합 여부는 GitHub에서 확인하세요. pr_linked는 수정 완료를 뜻하지 않으며, PR 생성·병합·Play Console 배포를 실행하지 않습니다. 피드백 상태와 보상도 자동으로 변경하지 않습니다.
수정 작업 객체
| 필드 | 형식 | 의미 |
|---|---|---|
id, appId | UUID | 작업 및 앱 ID |
title, instructions, acceptanceCriteria | string | 제목·수정 지시·완료 기준 |
issueIds | UUID[] | 연결한 피드백 ID. 정렬된 배열 |
status | open | pr_linked | 생성 또는 PR 연결 상태 |
pullRequestUrl | string | null | 연결 전에는 null |
createdBy | UUID | 작업을 만든 앱 소유자 |
createdAt, updatedAt | ISO 8601 string | 생성 및 마지막 변경 시각 |
현재 작업 본문 수정·삭제, PR 교체·해제, 실행 담당자 지정 API는 제공하지 않습니다.