DillieDocs
dillie.work

프로젝트 만들기와 계층

CLI 로 프로젝트를 만들고, 그 프로젝트의 계층 규칙(어떤 이슈 타입이 최상위에 오고 어떤 타입 밑에 무엇을 달 수 있는가)을 확인하고 바꾸는 법을 다룬다. 계층 규칙은 프로젝트마다 다르다 — 같은 템플릿으로 만든 프로젝트끼리도 다를 수 있으므로 매번 조회한다.

예시의 ACME 는 자기 프로젝트 키로 바꿔 쓴다.

프로젝트 만들기

프로젝트는 일의 경계다. 담당자·일정·완료 판정이 따로 도는 단위면 새 프로젝트를 만들고, 같은 흐름 안의 갈래면 그 프로젝트의 계층으로 표현한다. 주제마다 프로젝트를 만들면 이슈 키가 흩어져 검색이 쪼개지고, 진척률이 따로 계산돼 전체가 어디쯤인지 보이지 않는다.

dillie --agent project projects create --data '{"name":"New Service","key":"ACME","template":"agile-scrum"}'
  • template — agile-scrum 은 스프린트를 쓰는 애자일 프로젝트, agile-kanban 은 스프린트를 끈 애자일 프로젝트다. 생략하면 이슈 타입 필드·계층·상태 전이 규칙이 없는 일반 리스트로 만들어진다.
  • includeInitiative — 애자일 템플릿에서만 의미가 있고 기본은 true 다. true 면 이니셔티브 타입과 initiative → epic 규칙이 더해지고 이니셔티브도 최상위에 올 수 있다. 어느 쪽이든 에픽·스토리·태스크·버그 같은 타입은 최상위에 둘 수 있다.
  • key — 대문자로 시작하는 대문자·숫자 2~10자(^[A-Z][A-Z0-9]{1,9}$)다. 모든 이슈 키의 접두어(ACME-123)가 된다.

키는 직접 지정한다. 생략하면 이름에서 키를 만드는데, 라틴 문자로 키를 만들 수 없는 이름(예: 한글 이름)이면 이슈 키 없이 만들어진다. 키는 같은 워크스페이스 안에서 유일해야 하고, 이미 있으면 409 로 거부된다.

키는 나중에 바꿀 수 있지만, 바꾸면 그 프로젝트의 모든 이슈 키가 새 접두어로 다시 쓰인다. 커밋 메시지나 문서에 적어 둔 예전 이슈 키는 더 이상 그 아이템을 가리키지 않으므로, 처음부터 짧고 바꾸지 않을 키를 고른다.

다른 워크스페이스에 만들기

프로젝트는 지금 선택된 워크스페이스에 만들어진다. 그 실행만 다른 워크스페이스에 만들려면 --workspace 나 DILLIE_WORKSPACE 로 지정한다(CLI 0.21.0 이상).

dillie --agent --workspace <tenantId> project projects create --data '{"name":"New Service","key":"ACME","template":"agile-scrum"}'

키는 워크스페이스 안에서만 유일하므로, 다른 워크스페이스에 같은 키가 있어도 만들어진다. 여러 워크스페이스를 다룬다면 만들기 전에 전부에서 키를 확인한다(CLI 0.21.0 이상).

dillie --agent project projects list --all-workspaces

두 기능 모두 dillie login 의 기본 방식(브라우저·--device)으로 로그인한 세션이 필요하다. 워크스페이스 지정 규칙의 자세한 내용은 dillie CLI 로 일하기 — 워크스페이스 정하기에 있다.

프로젝트 계층 확인하기

어떤 타입이 최상위가 될 수 있고 어떤 타입이 어떤 타입의 자식이 될 수 있는지는 그 프로젝트의 설정이다. 일반적인 애자일 관행이나 다른 프로젝트에서 본 구조로 짐작하지 않는다.

dillie --agent describe ACME --fields fieldMap

응답에 hierarchy 블록이 있으면 세 가지가 들어 있다.

  • agileMode — 애자일이 켜져 있는가. true 일 때만 서버가 아래 규칙을 강제한다.
  • topLevelAllowed — 부모 없이 만들 수 있는 타입
  • allowedChildren — 부모 타입별로 허용되는 자식 타입

describe 는 요약이다. 프로젝트에 워크플로 설정이 없거나 계층 표가 비어 있으면 hierarchy 블록을 생략하는데, 블록이 없다는 것만으로는 규칙이 없는지 알 수 없다. 블록이 없거나 agileMode 를 확인해야 하면 다음 절대로 규칙을 직접 조회한다.

계층 규칙 직접 조회하기

계층과 상태 전이 규칙의 정본은 리스트 상세의 workProfile 이다.

dillie --agent project lists get ACME

workProfile 은 다음 셋 중 하나다.

workProfile 뜻 규칙
null 워크플로 설정이 없다(애자일 템플릿 없이 만든 프로젝트) 없다
agileMode: false 애자일이 꺼져 있다 없다. config 에 값이 남아 있어도 적용되지 않는다
agileMode: true 애자일이 켜져 있다 config 의 값이 실제 규칙이다

agileMode: true 일 때 config 에서 읽는 키는 다음과 같다.

애자일을 꺼도 config 의 값은 지워지지 않는다. 값이 있다는 것만으로 규칙이 있다고 읽지 않고 agileMode 를 함께 본다.

이슈 타입 채우기

describe 응답의 fields 에 role 이 ISSUE_TYPE 인 필드가 있는 프로젝트라면, 모든 아이템에 이슈 타입을 넣는다. 쓸 수 있는 값은 그 필드의 options 에 있는 옵션 id 다. 그 필드가 없는 프로젝트에 issueType 을 보내면 거부된다.

계층 규칙은 이슈 타입이 있는 아이템에만 적용된다. 타입 없이 만든 아이템은 검사 없이 통과하고, 부모-자식 연결만 있고 타입이 빈 아이템이 남는다. 응답만 보면 계층이 만들어진 것처럼 보이므로, 만든 뒤 되읽어 타입이 들어갔는지 확인한다.

dillie --agent project tasks get ACME ACME-1

응답 values 의 키는 필드 id 다. describe 의 fields[].id 와 대조해 이슈 타입 필드의 값을 찾는다.

검사는 생성할 때만이 아니라 수정·대량 수정·순서 바꾸기에서도 돈다. 부모의 타입을 바꾸면 그 밑의 기존 자식도 다시 검사된다. 그래서 타입을 비워 두고 만든 아이템에 나중에 타입을 넣으면 그때 거부될 수 있다.

계층 표(hierarchy)에 없는 타입을 부모로 둔 아이템 밑에는 타입이 있는 자식을 달 수 없다.

계층을 한 번에 만들기

부모를 만들고 id 를 받아 자식을 만드는 왕복 없이, 한 요청 안에서 앞선 아이템을 부모로 참조한다.

dillie --agent project tasks bulk-create ACME --data '[
  {"clientId":"e1","values":{"title":"결제 개편","issueType":"epic","_description":"## 배경\n…"}},
  {"parentClientId":"e1","values":{"title":"카드 결제 재시도","issueType":"story","_description":"## 배경\n…"}}
]'
  • clientId 는 이 요청 안에서만 쓰는 임시 이름이다. parentClientId 는 같은 배치에서 앞에 나온 아이템의 clientId 여야 하고, parentItemId 와 함께 쓸 수 없다.
  • 이슈 타입은 항목마다 values.issueType 으로 넣는다. --issue-type 옵션은 모든 항목을 같은 타입으로 덮어쓰므로 계층을 섞을 때는 쓰지 않는다.
  • 응답의 createdRefs 가 항목마다 { id, issueKey, clientId } 를 돌려준다. 어느 항목이 어떤 이슈 키가 됐는지 이것으로 대조한다.

벌크 생성은 전부 반영되거나 하나도 반영되지 않는다. 보내기 전에 --dry-run 으로 대상 건수와 앞쪽 몇 건을 확인할 수 있다. 자세한 내용은 찾기와 대량 정리 — 대량 생성하기에 있다.

계층 바꾸기

애자일이 켜진 프로젝트의 계층 규칙은 lists update-hierarchy 로 바꾼다. 먼저 계층 규칙 직접 조회하기대로 지금 규칙을 읽는다.

dillie --agent project lists update-hierarchy ACME \
  --data '{"merge":true,"hierarchy":{"story":["subtask","e2e","task"]}}'

본문의 hierarchy 와 topLevelAllowed 중 보낸 것만 바뀌고, 보내지 않은 것은 그대로 남는다. merge 는 보낸 값을 어떻게 반영할지 정한다.

merge hierarchy topLevelAllowed
false(기본) 보낸 표로 통째로 교체 보낸 목록으로 교체
true 보낸 부모 타입마다 그 자식 목록을 통째로 교체. 보내지 않은 부모 타입은 그대로 기존 목록과 합친다

merge: true 도 자식 목록을 더해 주지 않는다. 이미 있는 부모 타입을 보내면 그 부모의 자식 목록이 보낸 것으로 바뀐다. 위 예시처럼 자식 하나를 더하려면 기존 자식까지 함께 적는다. 반대로 보낸 부모 타입의 목록에서 빠뜨린 자식은 사라진다. merge: true 로 지울 수 없는 것은 보내지 않은 부모 타입과 최상위 허용 타입이다 — 그것들을 지우려면 merge: false 로 원하는 전체를 보낸다.

  • 값은 라벨이 아니라 이슈 타입 필드의 옵션 id 다. 그 필드에 없는 id 를 보내면 거부된다.
  • 자기 자신을 자식으로 두거나 순환을 만드는 규칙은 거부된다.
  • 응답은 바뀐 결과(agileMode·config)다. 의도한 표가 됐는지 응답으로 확인한다.

문제 해결

상태 코드 일반을 읽는 법은 dillie CLI 로 일하기 — 문제 해결에 있다.

프로젝트를 찾을 수 없다

오류 메시지가 어느 워크스페이스에서 찾았는지 알려 준다. 다른 워크스페이스의 프로젝트라면 projects list --all-workspaces 로 어디 있는지 찾고, --workspace 로 그 워크스페이스를 지정해 다시 실행한다.

같은 키의 프로젝트가 이미 있다(409)

그 워크스페이스에 같은 키의 프로젝트가 있다. 다른 키를 고른다.

계층 규칙에 막혔다

400 으로 오고, 메시지가 막힌 부모 타입과 자식 타입을 말한다. 부모 없이 만들다 막혔으면 부모 자리에 (top-level) 이 나온다. 같은 조합은 다시 보내도 통과하지 않는다. 계층 규칙 직접 조회하기대로 허용되는 조합을 읽고 부모나 타입을 고친다.

계층 바꾸기가 거부됐다

  • 애자일이 꺼져 있거나 워크플로 설정이 없는 프로젝트다. 이때 메시지는 구체적인 사유를 말하지 않으므로 lists get 으로 workProfile 을 확인한다.
  • 이슈 타입 필드에 없는 옵션 id 를 보냈다. 이니셔티브 없이 만든 프로젝트에 initiative 를 보내는 경우가 그렇다.
  • 자기 루프나 순환이 생기는 규칙을 보냈다.