paint-brush
수식과 구조 Jira 플러그인을 사용하여 시간과 신경을 절약하세요~에 의해@ipolubentcev
874 판독값
874 판독값

수식과 구조 Jira 플러그인을 사용하여 시간과 신경을 절약하세요

~에 의해 Ivan Polubentsev36m2023/10/29
Read on Terminal Reader

너무 오래; 읽다

Jira Structure 플러그인을 사용한 공식은 놀랍습니다. 테이블을 생성하고, 작업 작업을 단순화하고, 릴리스와 프로젝트를 분석하면서 게임을 향상시킬 수 있습니다.
featured image - 수식과 구조 Jira 플러그인을 사용하여 시간과 신경을 절약하세요
Ivan Polubentsev HackerNoon profile picture
0-item
1-item

Jira용 Structure 플러그인은 일상적인 작업 및 분석 작업에 매우 유용합니다. Jira 티켓의 시각화 및 구조화를 새로운 수준으로 끌어올려 이 모든 작업을 즉시 수행합니다.


그리고 모든 사람이 아는 것은 아니지만 구조 수식의 기능은 여러분을 놀라게 할 수 있습니다. 수식을 사용하면 작업 작업을 크게 단순화할 수 있는 매우 유용한 테이블을 만들 수 있으며, 가장 중요한 것은 릴리스, 에픽 및 프로젝트에 대한 심층 분석을 수행하는 데 유용하다는 것입니다.


번다운(Burndown) 차트를 표시하거나 작업이 포함된 테이블에 티켓 상태를 표시하는 것은 어떻습니까?


이 문서에서는 가장 간단한 예부터 시작하여 복잡하지만 유용한 사례로 끝나는 자신만의 수식을 만드는 방법을 살펴보겠습니다.


그렇다면 이 글은 누구를 위한 글인가요? ALM Works 웹 사이트의 공식 문서가 독자들의 탐구를 기다리고 있는데 왜 기사를 작성하는지 궁금할 수도 있습니다. 사실입니다. 그러나 나는 Structure가 이렇게 광범위한 기능을 숨기고 있다는 사실을 조금도 생각하지 못한 사람 중 한 명입니다. "잠깐만요, 이것은 항상 옵션이었나요?!" 그 깨달음으로 저는 수식과 구조를 사용하여 어떤 일을 할 수 있는지 아직 모르는 사람들이 있을 수도 있다는 생각을 하게 되었습니다.


이 글은 이미 수식에 익숙한 사람들에게도 유용할 것입니다. 사용자 정의 필드를 사용하기 위한 몇 가지 흥미롭고 실용적인 옵션을 배우게 되며 아마도 프로젝트 에 그 중 일부를 빌릴 수도 있습니다. 그건 그렇고, 자신만의 흥미로운 예가 있다면 댓글로 공유해 주시면 감사하겠습니다. .


각 예제는 문제 설명부터 코드 설명까지 자세히 분석되어 질문이 남지 않을 만큼 철저합니다. 물론, 설명과 함께 각 예제는 분석을 깊이 파고들지 않고도 직접 시도해 볼 수 있는 코드로 설명되어 있습니다.


읽고 싶지 않지만 공식에 관심이 있다면 ALM Works 웹 세미나를 확인하세요. 40분 동안 기본 사항을 설명합니다. 정보는 매우 압축된 방식으로 표시됩니다.


예제를 이해하는 데 추가 지식이 필요하지 않으므로 Jira 및 Structure를 사용해본 적이 있는 사람이라면 누구나 문제 없이 테이블에서 예제를 반복할 수 있습니다.


개발자는 Expr 언어를 사용하여 상당히 유연한 구문을 제공했습니다. 기본적으로 여기서의 철학은 "원하는 대로 작성하면 작동합니다"입니다.


자, 시작해 봅시다!


왜 수식이 필요한가요?

그렇다면 우리는 왜 공식을 사용하고 싶을까요? 글쎄, 때때로 "담당자", "스토리 포인트" 등과 같은 표준 Jira 필드가 충분하지 않은 것으로 나타났습니다. 또는 특정 필드에 대한 양을 계산하고, 버전별로 남은 용량을 표시하고, 작업 상태가 몇 번이나 변경되었는지 확인해야 합니다. 어쩌면 구조를 더 쉽게 읽을 수 있도록 여러 필드를 하나로 병합하고 싶을 수도 있습니다.


이러한 문제를 해결하려면 수식이 필요하며 이를 사용하여 사용자 정의 필드를 만듭니다.


가장 먼저 해야 할 일은 공식이 어떻게 작동하는지 이해하는 것입니다. 이를 통해 문자열에 일종의 작업을 적용할 수 있습니다. 많은 작업을 구조에 업로드하므로 수식이 전체 테이블의 각 줄에 적용됩니다. 일반적으로 모든 작업은 이러한 라인의 작업 작업을 목표로 합니다.


따라서 수식에 "담당자"와 같은 일부 Jira 필드를 표시하도록 요청하면 수식이 각 작업에 적용되며 또 다른 "담당자" 열이 표시됩니다.


수식은 다음과 같은 몇 가지 기본 엔터티로 구성됩니다.

  • 변수 — Jira 필드에 액세스하고 중간 결과를 저장하기 위한 것
  • 내장 함수 - 미리 정의된 작업을 수행합니다. 예를 들어 날짜 사이의 시간을 계산하거나 배열의 데이터를 필터링합니다.
  • 사용자 정의 함수 - 고유한 계산이 필요한 경우
  • 옵션에 대한 "날짜/시간", "기간", "숫자" 또는 "위키 마크업"과 같은 다양한 형태의 결과 표시.


공식 알아보기

몇 가지 예를 통해 수식과 해당 구문에 더 익숙해지고 6가지 실제 사례를 살펴보겠습니다.


각 예를 살펴보기 전에 어떤 구조 기능을 사용하고 있는지 알아보겠습니다. 아직 설명되지 않은 새로운 기능은 굵게 표시됩니다. 다음 각 예는 점점 더 복잡해집니다. 중요한 공식 기능을 점진적으로 소개하기 위해 배열되었습니다.


매번 보게 될 기본 구조는 다음과 같습니다.

  • 문제
  • 제안된 솔루션
  • 사용된 구조 기능
  • 코드 예시
  • 솔루션 분석


다음 예제는 변수 매핑부터 복잡한 배열까지 다양한 주제를 다룹니다.

  • 작업에 대한 작업 시작 및 종료 날짜를 표시하는 두 가지 예(표시가 다른 옵션)
  • 상위 작업 — 상위 작업의 유형과 이름 표시
  • 하위 작업의 스토리 포인트 합계와 이러한 평가 상태
  • 작업 상태의 최근 변경 사항 표시
  • 휴일(주말) 및 추가 상태를 제외한 근무 시간 계산


수식 만들기

먼저 수식을 사용하여 사용자 정의 필드를 만드는 방법을 알아 보겠습니다. Structure의 오른쪽 상단 부분에 있는 모든 열 끝에는 "+" 아이콘이 있습니다. 이를 클릭하세요. 나타나는 필드에 "Formula…"라고 쓰고 해당 항목을 선택하십시오.


수식 만들기


수식 저장

수식 저장에 대해 논의해 보겠습니다. 불행하게도 특정 수식을 어딘가에 별도로 저장하는 것은 여전히 불가능합니다(저처럼 노트북에만 가능). ALM Works 웹 세미나에서 팀은 수식 은행을 작업 중이지만 현재 수식을 저장하는 유일한 방법은 수식과 함께 전체 보기를 저장하는 것이라고 언급했습니다.


수식 작업이 끝나면 구조의 보기(파란색 별표로 표시될 가능성이 높음)를 클릭하고 "저장"을 클릭하여 현재 보기를 덮어써야 합니다. 또는 "다른 이름으로 저장..."을 클릭하여 새 보기를 만들 수 있습니다. (새 보기는 기본적으로 비공개이므로 다른 Jira 사용자가 사용할 수 있도록 하는 것을 잊지 마세요.)


수식은 특정 보기의 나머지 필드에 저장되며 "세부 정보 보기" 메뉴의 "고급" 탭에서 볼 수 있습니다.


버전 8.2부터 Structure에는 이제 세 번의 빠른 클릭으로 수식을 저장할 수 있는 기능이 있습니다.

저장 대화 상자는 수식 편집 창에서 사용할 수 있습니다. 이 창이 열려 있지 않으면 원하는 열의 삼각형 ▼ 아이콘을 클릭하세요.


수식 저장


편집 창에는 "저장된 열" 필드가 있으며 오른쪽에는 파란색 알림 아이콘이 있습니다. 이는 수식의 변경 사항이 저장되지 않았음을 의미합니다. 이 아이콘을 클릭하고 "다른 이름으로 저장..." 옵션을 선택하세요.


저장된 열


그런 다음 열(수식)의 이름을 입력하고 저장할 공간을 선택합니다. 개인 목록에 저장하려면 “내 열”을 선택하세요. "글로벌" - 공식이 일반 목록에 저장되어 구조의 모든 사용자가 편집할 수 있습니다. “저장”을 클릭하세요.


저장을 클릭하세요


이제 공식이 저장되었습니다. 어떤 구조로든 로드하거나 어디에서나 다시 저장할 수 있습니다. 수식을 다시 저장하면 해당 수식이 사용되는 모든 구조에서 업데이트됩니다.


변수 매핑도 수식과 함께 저장되지만 매핑에 대해서는 나중에 설명하겠습니다.


이제 예제로 넘어가겠습니다!


작업에 대한 작업 시작 및 종료 날짜 표시

마지막 두 열의 맞춤 날짜

문제

작업 목록과 해당 작업을 수행하기 위한 시작 및 종료 날짜가 포함된 테이블이 필요합니다. 별도의 Excel-Gantt로 내보내려면 테이블도 필요합니다. 안타깝게도 Jira와 Structure는 이러한 날짜를 기본적으로 제공하는 방법을 모릅니다.

제안 된 해결책

시작 및 종료 날짜는 특정 상태로의 전환 날짜이며, 이 경우에는 "진행 중" 및 "종료"입니다. 이러한 날짜를 가져와서 각각을 별도의 필드에 표시해야 합니다(추가로 Gantt로 내보내는 데 필요함). 따라서 두 개의 필드(두 개의 수식)가 있습니다.


사용된 구조 기능

  1. 변수 매핑
  2. 표시 형식을 조정하는 기능


코드 예시

시작 날짜 필드:

 firstTransitionToStart


종료일 필드:

 latestTransitionToDone


솔루션 분석

이 경우 코드는 시작 날짜 필드에 대한 단일 변수인 firstTransitionToStart이고 두 번째 필드에 대한 최신TransitionToDone입니다.


지금은 시작 날짜 필드에 중점을 두겠습니다. 우리의 목표는 작업이 "진행 중" 상태로 전환된 날짜(작업의 논리적 시작에 해당)를 얻는 것입니다. 따라서 변수 이름은 나중에 추측할 필요가 없도록 매우 명시적으로 "첫 번째 전환"으로 지정됩니다. 시작".


날짜를 변수로 만들기 위해 변수 매핑을 사용합니다. "저장" 버튼을 클릭하여 공식을 저장해 보겠습니다.


수식을 저장하려면 클릭하세요.


변수는 옆에 느낌표와 함께 "변수" 섹션에 나타났습니다. 구조는 변수를 Jira의 필드에 연결할 수 없으며 우리가 직접 연결해야 함(예: 매핑)을 나타냅니다.


변수를 클릭하고 매핑 인터페이스로 이동합니다. 필드 또는 필요한 작업을 선택합니다. "전환 날짜..." 작업을 찾습니다. 그렇게 하려면 선택 필드에 "전환"을 입력하세요. 한 번에 여러 가지 옵션이 제공되며 그 중 하나가 "진행 중으로의 첫 번째 전환"입니다. 그러나 매핑이 어떻게 작동하는지 보여주기 위해 "전환 날짜..." 옵션을 선택해 보겠습니다.


매핑 구성


그런 다음 전환이 발생한 상태와 전환 순서(첫 번째 또는 마지막)를 선택해야 합니다.


"상태" - "상태: 진행 중"(또는 워크플로의 해당 상태) 및 "전환" - "상태로의 첫 번째 전환"을 선택하거나 입력합니다. 작업에 대한 작업 시작이 바로 첫 번째 전환이기 때문입니다. 해당 상태로 이동합니다.


원하는 카테고리를 선택하세요



"전환 날짜..." 대신에 처음에 제안된 옵션 "진행 중으로의 첫 번째 전환"을 선택했다면 결과는 거의 동일할 것입니다. 즉, 구조가 필요한 매개변수를 선택합니다. 유일한 것은 "상태: 진행 중" 대신 "범주: 진행 중"이 있다는 것입니다.


상태 카테고리와 상태의 차이점


중요한 기능을 언급하겠습니다. 상태와 카테고리는 서로 다른 것입니다. 상태는 특정 상태이며 명확하지만 카테고리에는 여러 상태가 포함될 수 있습니다. 범주는 "할 일", "진행 중", "완료"의 세 가지뿐입니다. Jira에서는 일반적으로 각각 회색, 파란색, 녹색으로 표시됩니다. 상태는 다음 범주 중 하나에 속해야 합니다.

이와 같은 경우에는 동일한 카테고리의 상태와 혼동을 피하기 위해 특정 상태를 표시하는 것이 좋습니다. 예를 들어 프로젝트에는 "To Do" 범주에 "Open"과 "QA Queue"라는 두 가지 상태가 있습니다.


우리의 예로 돌아가 보겠습니다.


필요한 옵션을 선택했으면 "< 변수 목록으로 돌아가기"를 클릭하여 firstTransitionToStart 변수에 대한 매핑 옵션을 완료할 수 있습니다. 모든 작업을 올바르게 수행하면 녹색 확인 표시가 표시됩니다.


일반에는 기본값(밀리초)이 표시됩니다.


동시에 사용자 정의 필드에는 전혀 날짜처럼 보이지 않는 이상한 숫자가 표시됩니다. 우리의 경우 수식의 결과는 firstTransitionToStart 변수의 값이 되며 해당 값은 1970년 1월 이후의 밀리초입니다. 올바른 날짜를 얻으려면 특정 수식 표시 형식을 선택해야 합니다.


형식 선택은 편집 창 맨 아래에 있습니다. 기본적으로 "일반"이 선택되어 있습니다. 날짜를 정확하게 표시하려면 “날짜/시간”이 필요합니다.


일반 대신 날짜/시간을 선택하세요.


두 번째 필드인 lateTransitionToDone에 대해서도 동일한 작업을 수행합니다. 유일한 차이점은 매핑할 때 상태가 아닌 "완료" 범주를 이미 선택할 수 있다는 것입니다(일반적으로 명확한 작업 완료 상태는 하나만 있기 때문입니다). "완료" 범주에 대한 가장 최근의 전환에 관심이 있으므로 전환 매개변수로 "최신 전환"을 선택합니다.


두 필드의 최종 결과는 다음과 같습니다.


날짜가 포함된 최종 보기


이제 자체 표시 형식을 사용하여 동일한 결과를 얻는 방법을 살펴보겠습니다.


자체 형식으로 날짜 표시

사용자 정의 형식의 예


문제

간트 테이블에 대한 특별한 형식인 "01.01.2022"가 필요하기 때문에 이전 예제의 날짜 표시 형식이 만족스럽지 않습니다.


제안 된 해결책

Structure에 내장된 함수를 사용하여 날짜를 표시하고 우리에게 적합한 형식을 지정해 보겠습니다.


사용된 구조 특징

  1. 변수 매핑
  2. Expr 함수


코드 예시

 FORMAT_DATETIME(firstTransitionToStart;"dd.MM.yyyy")


솔루션 분석

개발자는 자체 형식으로 날짜를 표시하는 별도의 기능을 포함하여 다양한 기능을 제공했습니다. FORMAT_DATETIME; 그것이 우리가 사용할 것입니다. 이 함수는 날짜와 원하는 형식의 문자열이라는 두 가지 인수를 사용합니다.


이전 예제와 동일한 매핑 규칙을 사용하여 firstTransitionToStart 변수(첫 번째 인수)를 설정합니다. 두 번째 인수는 형식을 지정하는 문자열이며 "dd.MM.yyyy"와 같이 정의합니다. 이는 우리가 원하는 형식인 "01.01.2022"에 해당합니다.


따라서 우리의 공식은 즉시 원하는 형식의 결과를 제공합니다. 따라서 필드 설정에서 "일반" 옵션을 유지할 수 있습니다.


작업 종료 날짜가 있는 두 번째 필드도 같은 방식으로 수행됩니다. 결과적으로 구조는 아래 이미지와 같아야 합니다.


변환 후 최종 공급


원칙적으로 수식 구문 작업에는 큰 어려움이 없습니다. 변수가 필요하면 이름을 쓰세요. 함수가 필요하면 함수 이름을 쓰고 인수(필요한 경우)를 전달하면 됩니다.


Structure가 알 수 없는 이름을 발견하면 이를 변수라고 가정하고 자체 매핑을 시도하거나 도움을 요청합니다.


그런데 중요한 참고 사항: 구조는 대소문자를 구분하지 않으므로 firstTransitionToStart, firsttransitiontostart 및 firSttrAnsItiontOSrT는 동일한 변수입니다. 동일한 규칙이 함수에도 적용됩니다. 명확한 코드 스타일을 달성하기 위해 예제에서는 MSDN의 대문자 사용 규칙을 준수하려고 노력할 것입니다.


이제 구문을 자세히 살펴보고 결과를 표시하기 위한 특수 형식을 살펴보겠습니다.


상위 작업의 이름 표시

요약 앞에 부모의 이름이 표시됩니다.


문제

우리는 일반적인 작업(태스크, 버그 등)과 하위 작업이 있는 스토리 유형의 작업으로 작업합니다. 어느 시점에서는 직원이 특정 기간 동안 어떤 업무와 하위 업무를 수행했는지 알아내야 합니다.


문제는 많은 하위 작업이 "스토리 작업 중", "설정" 또는 "효과 활성화"라고 불리기 때문에 스토리 자체에 대한 정보를 제공하지 않는다는 것입니다. 그리고 특정 기간 동안의 작업 목록을 요청하면 다른 유용한 정보 없이 '스토리 작업'이라는 이름의 작업이 12개 제공됩니다.


우리는 목록이 작업과 상위 작업이라는 두 개의 열로 나누어진 보기를 원하므로 나중에 이러한 목록을 직원별로 그룹화할 수 있습니다.


제안 된 해결책

우리 프로젝트에는 작업이 상위 작업을 가질 수 있는 경우 두 가지 옵션이 있습니다.

  1. 작업은 하위 작업이고 해당 상위 작업은 스토리뿐입니다.
  2. 작업은 일반적인 작업(작업, 버그 등)이며 Epic이 있을 수도 있고 없을 수도 있습니다. 이 경우 작업에는 상위가 전혀 없습니다.


따라서 우리는 다음을 수행해야 합니다.

  1. 작업에 상위 작업이 있는지 확인
  2. 이 부모의 유형을 알아보세요
  3. "[부모 유형] 부모 이름" 구성표에 따라 이 작업의 유형과 이름을 계산합니다.


정보 인식을 단순화하기 위해 작업 유형의 텍스트, 즉 "[스토리]" 또는 "[에픽]"에 색상을 지정합니다.


우리가 사용할 것:

  1. 변수 매핑
  2. 상태
  3. 작업 필드에 대한 액세스
  4. 표시 형식 - 위키 마크업


코드 예시

 if( Parent.Issuetype = "Story"; """{color:green}[${Parent.Issuetype}]{color} ${Parent.Summary}"""; EpicLink; """{color:#713A82}[${EpicLink.Issuetype}]{color} ${EpicLink.EpicName}""" )


솔루션 분석

문자열을 출력하고 거기에 작업 유형과 이름을 삽입하기만 하면 된다면 수식이 if 조건으로 시작하는 이유는 무엇입니까? 작업 필드에 액세스하는 보편적인 방법이 없나요? 예, 하지만 작업과 에픽의 경우 이러한 필드의 이름이 다르며 해당 필드에도 다르게 액세스해야 합니다. 이는 Jira의 기능입니다.


차이점은 상위 검색 수준에서 시작됩니다. 하위 작업의 경우 상위는 "상위 문제" Jira 필드에 있고 일반 작업의 경우 에픽은 "에픽 링크" 필드에 있는 상위가 됩니다. 따라서 이러한 필드에 액세스하려면 두 가지 다른 옵션을 작성해야 합니다.


여기서 if 조건이 필요합니다. Expr 언어에는 조건을 처리하는 다양한 방법이 있습니다. 그들 사이의 선택은 취향의 문제입니다.


"엑셀과 유사한" 방법이 있습니다:

 if (condition1; result1; condition2; result2 … )


또는 좀 더 “코드와 유사한” 방법:

 if condition1 : result1 else if condition2 : result2 else result3


이 예에서는 첫 번째 옵션을 사용했습니다. 이제 단순화된 방식으로 코드를 살펴보겠습니다.

 if( Parent.Issuetype = "Story"; Some kind of result 1; EpicLink; Some kind of result 2 )


우리는 두 가지 명백한 조건을 봅니다.

  • Parent.Issuetype = "스토리"
  • 에픽링크


그들이 무엇을 하는지 알아보고 첫 번째인 Parent.Issuetype=”Story”부터 시작하겠습니다.


이 경우 Parent는 “Parent Issue” 필드에 자동으로 매핑되는 변수입니다. 위에서 논의한 것처럼 하위 작업의 상위 작업이 여기에 있어야 합니다. 점 표기법(.)을 사용하여 이 상위 속성, 특히 "문제 유형" Jira 필드에 해당하는 Issuetype 속성에 액세스합니다. 전체 Parent.Issuetype 행은 해당 작업이 존재하는 경우 상위 작업의 유형을 반환하는 것으로 나타났습니다.


게다가 개발자들이 이미 우리를 위해 최선을 다했기 때문에 우리는 아무것도 정의하거나 매핑할 필요가 없었습니다. 예를 들어 여기에는 언어에 사전 정의된 모든 속성(Jira 필드 포함)에 대한 링크가 있으며, 여기서는 추가 설정 없이 안전하게 액세스할 수 있는 모든 표준 변수 목록을 볼 수 있습니다.


따라서 첫 번째 조건은 상위 작업의 유형이 Story인지 확인하는 것입니다. 첫 번째 조건이 충족되지 않으면 상위 작업의 유형이 Story가 아니거나 전혀 존재하지 않는 것입니다. 그리고 이는 두 번째 조건인 EpicLink로 이어집니다.


실제로 이는 “Epic Link” Jira 필드가 채워졌는지(즉, 존재 여부를 확인하는 경우) 확인하는 경우입니다. EpicLink 변수도 표준이므로 매핑할 필요가 없습니다. 작업에 Epic Link가 있으면 조건이 충족되는 것으로 나타났습니다.


세 번째 옵션은 조건 중 어느 것도 충족되지 않는 경우, 즉 작업에 상위 링크나 Epic Link가 없는 경우입니다. 이 경우 아무것도 표시하지 않고 필드를 비워 둡니다. 결과가 전혀 나오지 않으므로 이 작업은 자동으로 수행됩니다.


조건을 알아냈으니 이제 결과를 살펴보겠습니다. 두 경우 모두 텍스트와 특수 서식이 포함된 문자열입니다.


결과 1(상위 항목이 Story인 경우):

 """{color:green}[${Parent.Issuetype}]{color} ${Parent.Summary}"""


결과 2(Epic Link가 있는 경우):

 """{color:#713A82}[${EpicLink.Issuetype}]{color} ${EpicLink.EpicName}"""


두 결과 모두 구조가 비슷합니다. 둘 다 출력 문자열의 시작과 끝 부분에 삼중따옴표 """로 구성되어 있으며, 시작 {color: COLOR} 블록과 닫는 {color} 블록의 색상 지정, 그리고 다음을 통해 수행된 작업으로 구성됩니다. $ 기호. 세 개의 따옴표는 내부에 변수, 연산 또는 서식 지정 블록(예: 색상)이 있음을 구조에 알려줍니다.


첫 번째 조건의 결과는 다음과 같습니다.

  1. 상위 작업 ${Parent.Issuetype} 유형 전송
  2. 대괄호 "[...]"로 묶습니다.
  3. 모든 것을 녹색으로 강조 표시하고 이 표현식 [${Parent.Issuetype}]을 색상 선택 블록 {color:green}…{color}에 넣습니다. 여기서는 "green"이라고 썼습니다.
  4. 마지막으로 공백 ${Parent.Summary}로 구분된 상위 작업의 이름을 추가합니다.


따라서 "[Story] Some task name"이라는 문자열을 얻습니다. 짐작하셨겠지만, 요약(Summary)도 표준 변수입니다. 이러한 문자열을 구성하는 방식을 더 명확하게 만들기 위해 공식 문서의 이미지를 공유하겠습니다.


공식 문서의 사용자 정의 행 구성표


비슷한 방식으로 두 번째 결과에 대한 문자열을 수집하되 16진수 코드를 통해 색상을 설정합니다. 에픽의 색상이 "#713A82"인 것을 알아냈습니다(댓글에 에픽의 더 정확한 색상을 제안하실 수 있습니다). Epic에 대해 변경되는 필드(속성)를 잊지 마세요. “Summary” 대신 “EpicName”을 사용하고, “Parent” 대신 “EpicLink”를 사용하세요.


결과적으로 우리 공식의 체계는 조건표로 표현될 수 있습니다.


조건: 상위 태스크가 존재하고 유형이 스토리입니다.

결과: 녹색 유형의 상위 작업과 해당 이름이 있는 줄입니다.

조건: Epic Link 필드가 채워져 있습니다.

결과: 유형과 이름의 서사적 색상이 포함된 선입니다.


해당 항목에는 기본적으로 "일반" 표시 옵션이 선택되어 있으며, 이를 변경하지 않으면 색상 변경 및 블록 식별 없이 일반 텍스트처럼 결과가 표시됩니다. 표시 형식을 "Wiki Markup"으로 변경하면 텍스트가 변환됩니다.


1) 일반 표시 - 기본적으로 일반 텍스트를 있는 그대로 표시합니다. 2) 일반을 Wiki 마크업으로 교체



이제 Jira 필드와 관련이 없는 변수, 즉 로컬 변수에 대해 알아 보겠습니다.


색상 표시로 스토리 포인트 계산

스토리 포인트 합계는 다양한 색상으로 강조 표시됩니다.


문제

이전 예에서 하위 작업이 있는 Story 유형의 작업을 사용하고 있다는 것을 배웠습니다. 이로 인해 추정치와 관련된 특별한 경우가 발생합니다. 스토리 점수를 얻기 위해 추상적인 스토리 포인트로 추정되는 하위 작업의 점수를 요약합니다.


접근 방식은 특이하지만 우리에게는 효과적입니다. 따라서 Story에는 추정치가 없고 하위 작업에는 있으면 문제가 없지만 Story와 하위 작업에 모두 추정치가 있는 경우 Structure의 표준 옵션인 "Σ Story Points"가 제대로 작동하지 않습니다.


하위 작업의 합에 Story의 추정치가 더해지기 때문입니다. 결과적으로 스토리에 잘못된 금액이 표시됩니다. 우리는 이를 방지하고 스토리에 설정된 추정치 및 하위 작업 합계와 불일치에 대한 표시를 추가하고 싶습니다.


제안 된 해결책

스토리에 견적이 설정되어 있는지 여부에 따라 달라지므로 몇 가지 조건이 필요합니다.


따라서 조건은 다음과 같습니다.


Story에 추정치가 없으면 하위 작업 추정치의 합계가 주황색으로 표시되어 이 값이 Story에 아직 설정되지 않았음을 나타냅니다.


Story에 추정치가 있는 경우 하위 작업 추정치의 합계에 해당하는지 확인하세요.

  • 일치하지 않으면 추정치를 빨간색으로 칠하고 그 옆에 괄호 안에 정확한 금액을 적습니다.
  • 추정치와 합계가 일치하면 녹색으로 추정치를 적으면 됩니다.


이러한 조건의 표현은 혼란스러울 수 있으므로 이를 체계적으로 표현해 보겠습니다.


텍스트 표시 옵션을 선택하는 알고리즘


사용된 구조 특징

  1. 변수 매핑
  2. 지역변수
  3. 집계 방법
  4. 정황
  5. 서식이 적용된 텍스트


코드 예시

 with isEstimated = storypoints != undefined: with childrenSum = sum#children{storypoints}: with isStory = issueType = "Story": with isErr = isStory AND childrenSum != storypoints: with color = if isStory : if isEstimated : if isErr : "red" else "green" else "orange": if isEstimated : """{color:$color}$storypoints{color} ${if isErr :""" ($childrenSum)"""}""" else """{color:$color}$childrenSum{color}"""


솔루션 분석

코드를 살펴보기 전에, 필요한 변수가 무엇인지 이해하기 위해 우리의 체계를 보다 "코드와 유사한" 방식으로 변환해 보겠습니다.


변수로 다시 작성된 동일한 알고리즘


이 계획에서 우리는 다음이 필요하다는 것을 알 수 있습니다:


조건 변수:

  • isEstimated(추정 가용성)
  • isError (스토리 추정과 합의 대응)


텍스트 색상의 변수 중 하나 - 색상


두 가지 추정 변수:

  • sum (하위 작업 추정의 합계)
  • sp(스토리 포인트)


또한 색상 변수는 견적의 가용성 및 라인의 작업 유형과 같은 여러 조건에 따라 달라집니다(아래 구성표 참조).


색상 선택 알고리즘


따라서 색상을 결정하려면 작업 유형이 Story인지 여부를 나타내는 또 다른 조건 변수 isStory가 필요합니다.


sp 변수(스토리포인트)는 표준입니다. 즉, 적절한 Jira 필드에 자동으로 매핑됩니다. 나머지 변수는 우리가 직접 정의해야 하며 해당 변수는 우리에게 국한됩니다.


이제 코드에서 구성표를 구현해 보겠습니다. 먼저 모든 변수를 정의해 보겠습니다.


 with isEstimated = storypoints != undefined: with childrenSum = sum#children{storypoints}: with isStory = issueType = "Story": with isErr = isStory AND childrenSum != storypoints:


행은 동일한 구문 체계(with 키워드, 변수 이름, 행 끝에 콜론 기호 ":")로 통합됩니다.


지역 변수 선언 구문


with 키워드는 지역 변수(및 사용자 정의 함수, 이에 대한 자세한 내용은 별도의 예에서)를 나타내는 데 사용됩니다. 다음에는 매핑할 필요가 없는 변수가 사용된다는 것을 수식에 알려줍니다. 콜론 ":"은 변수 정의의 끝을 표시합니다.


따라서 isEstimated 변수를 생성합니다(이 경우는 중요하지 않음을 기억하세요). 스토리 포인트 필드가 채워졌는지 여부에 따라 1 또는 0을 저장합니다. 이전에 같은 이름의 로컬 변수를 만들지 않았기 때문에(예: storypoints = … :)) storypoints 변수가 자동으로 매핑됩니다.


정의되지 않은 변수는 무언가가 존재하지 않음을 나타냅니다(다른 언어에서는 null, NaN 등). 따라서 스토리포인트 != 정의되지 않음이라는 표현은 "스토리 포인트 필드가 채워졌나요?"라는 질문으로 읽을 수 있습니다.


다음으로 모든 하위 작업의 스토리 포인트 합계를 결정해야 합니다. 이를 위해 로컬 변수 childrenSum을 생성합니다.


 with childrenSum = sum#children{storypoints}:


이 합계는 집계 함수를 통해 계산됩니다. (이와 같은 기능에 대해서는 공식 문서 에서 읽을 수 있습니다.) 간단히 말해서 Structure는 현재 뷰의 계층 구조를 고려하여 작업과 함께 다양한 작업을 수행할 수 있습니다.


우리는 sum 함수를 사용하고, 그 외에도 "#" 기호를 사용하여 합계 계산을 현재 줄의 모든 하위 작업으로만 제한하는 설명 하위 항목을 전달합니다. 중괄호 안에는 어떤 필드를 요약하고 싶은지 표시합니다. 즉, 스토리포인트에 추정이 필요합니다.


다음 지역 변수인 isStory는 현재 줄의 작업 유형이 Story인지 여부라는 조건을 저장합니다.


 with isStory = issueType = "Story":


이전 예에서 친숙한 issueType 변수, 즉 원하는 필드에 자체적으로 매핑되는 작업 유형을 살펴보겠습니다. 우리가 이렇게 하는 이유는 이것이 표준 변수이고 이전에 with를 통해 정의한 적이 없기 때문입니다.


이제 isErr 변수를 정의해 보겠습니다. 이는 하위 작업 합계와 Story 추정치 간의 불일치를 나타냅니다.


 with isErr = isStory AND childrenSum != storypoints:


여기서는 앞서 만든 isStory 및 childrenSum 지역 변수를 사용하고 있습니다. 오류 신호를 보내려면 두 가지 조건이 동시에 충족되어야 합니다. 문제 유형이 Story(isStory)이고 (AND) 하위 포인트의 합계(childrenSum)가 작업에 설정된 추정치(storypoints)와 같지 않습니다(!=). ). JQL과 마찬가지로 AND 또는 OR와 같은 조건을 생성할 때 링크 단어를 사용할 수 있습니다.


각 지역 변수의 줄 끝에는 ":" 기호가 있습니다. 변수를 정의하는 모든 작업이 끝난 후 마지막에 있어야 합니다. 예를 들어, 변수 정의를 여러 줄로 나누어야 하는 경우 콜론 ":"은 마지막 작업 뒤에만 배치됩니다. color 변수를 사용한 예에서와 같이 텍스트의 색상입니다.


 with color = if isStory : if isEstimated : if isErr : "red" else "green" else "orange":


여기서는 ":"을 많이 볼 수 있지만 역할은 다릅니다. if isStory 뒤의 콜론은 isStory 조건의 결과입니다. 구성을 상기해 봅시다: if 조건: 결과. 변수를 정의하는 좀 더 복잡한 형태로 이 구성을 제시해 보겠습니다.


 with variable = (if condition: (if condition2 : result2 else result3) ):


if Condition2 : result2 else result3은 말하자면 첫 번째 조건의 결과이고 맨 끝에는 변수 정의를 완료하는 콜론 ":"이 있는 것으로 나타났습니다.


언뜻 보면 색상 정의가 복잡해 보일 수 있지만 실제로 여기에서는 예제 시작 부분에 제시된 색상 정의 구성표를 설명했습니다. 첫 번째 조건의 결과로 또 다른 조건, 즉 중첩된 조건과 그 안에 또 다른 조건이 시작됩니다.


그러나 최종 결과는 이전에 제시된 계획과 약간 다릅니다.


 if isEstimated : """{color:$color}$storypoints{color} ${if isErr :""" ($childrenSum)"""}""" else """{color:$color}$childrenSum{color}"""


구성표에서처럼 코드에 “{color}$sp”를 두 번 쓸 필요가 없습니다. 우리는 사물에 대해 더 똑똑해질 것입니다. 분기에서 작업에 추정치가 있는 경우 항상 {color: $color}$storypoints{color}(즉, 필요한 색상의 스토리 포인트 추정치)를 표시하고 오류가 있는 경우 공백 뒤에는 하위 작업 추정치의 합계($childrenSum)를 추가합니다.


오류가 없으면 추가되지 않습니다. 또한 변수를 정의하지 않고 조건을 통해 최종 결과를 표시하기 때문에 “:” 기호가 없다는 사실에도 주목합니다.


아래 이미지의 "∑SP(mod)" 필드에서 작업을 평가할 수 있습니다. 스크린샷에는 다음 두 가지 추가 필드가 구체적으로 표시되어 있습니다.


  • "스토리 포인트" - 스토리 포인트 추정치(표준 Jira 필드)
  • “∑ 스토리 포인트” — 금액을 잘못 계산하는 구조 표준 사용자 정의 필드입니다.


필드의 최종 보기 및 표준 스토리 포인트 및 ∑ 스토리 포인트 필드와의 비교


이러한 예제를 통해 대부분의 문제를 해결하는 데 도움이 되는 구조 언어의 주요 기능을 분석했습니다. 이제 두 가지 유용한 기능인 함수와 배열을 살펴보겠습니다. 우리만의 사용자 정의 함수를 만드는 방법을 살펴보겠습니다.


마지막 변경사항

왼쪽의 이모티콘에 주목하세요. 이는 사용자 정의 필드를 나타냅니다.


문제

때로는 스프린트에 많은 작업이 있어서 작은 변경 사항을 놓칠 수도 있습니다. 예를 들어, 새로운 하위 작업을 놓치거나 스토리 중 하나가 다음 단계로 이동했다는 사실을 놓칠 수 있습니다. 작업의 최신 중요한 변경 사항을 알려주는 도구가 있으면 좋을 것입니다.


제안 된 해결책

우리는 어제 이후 발생한 세 가지 유형의 작업 상태 변경에 관심이 있습니다. 작업 작업을 시작했고, 새 작업이 나타났으며, 작업이 종료되었습니다. 또한 "하지 않음"이라는 해결 방법으로 작업이 종료되는 것을 확인하는 것도 유용합니다.


이를 위해 최신 변경 사항을 담당하는 이모티콘 문자열이 포함된 필드를 만듭니다. 예를 들어, 어제 작업이 생성되어 작업을 시작했다면 해당 작업에는 "진행 중"과 "새 작업"이라는 두 개의 이모티콘이 표시됩니다.


예를 들어 "진행 중" 상태로의 전환 날짜 또는 별도의 "해결" 필드와 같은 여러 추가 필드를 표시할 수 있는 경우 이러한 사용자 정의 필드가 필요한 이유는 무엇입니까? 대답은 간단합니다. 사람들은 다양한 분야에 위치하며 분석이 필요한 텍스트보다 이모티콘을 더 쉽고 빠르게 인식합니다. 이 공식은 모든 것을 한곳에 모아서 분석해 주므로 더 유용한 작업에 드는 노력과 시간을 절약할 수 있습니다.


다양한 이모티콘이 어떤 역할을 하는지 알아봅시다.

  • *️⃣ 새 작업을 표시하는 가장 일반적인 방법입니다.
  • ✅ 완료된 작업을 표시합니다
  • ❌ 취소하기로 결정한 작업을 나타냅니다(“하지 않을 것”).
  • 🚀는 작업을 시작하기로 결정했다는 의미입니다(이 이모티콘은 우리 팀에 적합하지만 귀하에게는 다를 수 있습니다).


사용된 구조 특징

  1. 변수 매핑
  2. Expr 언어 방법
  3. 지역 변수
  4. 정황
  5. 우리 자신의 기능


코드 예시

 if defined(issueType): with now = now(): with daysScope = 1.3: with workDaysBetween(today, from)= ( with weekends = (Weeknum(today) - Weeknum(from)) * 2: HOURS_BETWEEN(from;today)/24 - weekends ): with daysAfterCreated = workDaysBetween(now,created): with daysAfterStart = workDaysBetween(now,latestTransitionToProgress): with daysAfterDone = workDaysBetween(now, resolutionDate): with isWontDo = resolution = "Won't Do": with isRecentCreated = daysAfterCreated >= 0 and daysAfterCreated <= daysScope and not(resolution): with isRecentWork = daysAfterStart >= 0 and daysAfterStart <= daysScope : with isRecentDone = daysAfterDone >= 0 and daysAfterDone <= daysScope : concat( if isRecentCreated : "*️⃣", if isRecentWork : "🚀", if isRecentDone : "✅", if isWontDo : "❌")

솔루션 분석


우선 관심 있는 이벤트를 결정하는 데 필요한 전역 변수에 대해 생각해 보겠습니다. 어제 이후로 다음과 같은 경우가 있는지 알아야 합니다.

  • 작업이 생성되었습니다.
  • 상태가 '진행중'으로 변경되었습니다.
  • 해결 방법을 찾았습니다(그리고 어떤 해결 방법인지)


새로운 매핑 변수와 함께 기존 변수를 사용하면 이러한 모든 조건을 확인하는 데 도움이 됩니다.

  • 생성됨 — 작업 생성 날짜
  • 최신TransitionToProgress — "진행 중" 상태로 전환되는 최신 날짜(이전 예에서와 같이 매핑)
  • ResolutionDate — 작업 완료 날짜
  • 해상도 - 해상도 텍스트


코드로 넘어 갑시다. 첫 번째 줄은 작업 유형이 존재하는지 확인하는 조건으로 시작됩니다.


 if defined(issueType):


이는 지정된 필드의 존재를 확인하는 내장 정의 함수를 통해 수행됩니다. 수식 계산을 최적화하기 위해 검사가 수행됩니다.


선이 작업이 아닌 경우 쓸모없는 계산으로 구조를 로드하지 않습니다. if 뒤의 모든 코드는 결과, 즉 if(조건:결과) 구성의 두 번째 부분이라는 것이 밝혀졌습니다. 조건이 충족되지 않으면 코드도 작동하지 않습니다.


계산을 최적화하려면 now = now():가 포함된 다음 줄도 필요합니다. 또한 코드에서는 다른 날짜를 현재 날짜와 여러 번 비교해야 합니다. 같은 계산을 여러번 하지 않기 위해 이 날짜를 한번 계산해서 이제 로컬변수로 만들어보겠습니다.


우리의 '어제'를 따로 보관하는 것도 좋을 것 같아요. 경험적으로 편리한 "어제"는 1.3일로 바뀌었습니다. 이것을 daysScope = 1.3:으로 변수로 만들어 보겠습니다.


이제 두 날짜 사이의 일수를 여러 번 계산해야 합니다. 예를 들어 현재 날짜와 작업 시작 날짜 사이입니다. 물론 우리에게 딱 맞는 DAYS_BETWEEN 함수가 내장되어 있습니다. 그러나 예를 들어 작업이 금요일에 생성된 경우 실제로 1.3일 이상이 경과했기 때문에 월요일에는 새 작업에 대한 알림이 표시되지 않습니다. 게다가 DAYS_BETWEEN 함수는 총 일수만 계산하는데(즉, 0.5일이 0일이 됨) 이 역시 우리에게는 적합하지 않습니다.


우리는 요구 사항을 만들었습니다. 즉, 해당 날짜 사이의 정확한 영업일 수를 계산해야 합니다. 맞춤 기능이 이에 도움이 될 것입니다.


선언 로컬 함수의 구문


정의 구문은 지역 변수를 정의하는 구문과 매우 유사합니다. 유일한 차이점이자 추가되는 점은 첫 번째 대괄호에 있는 선택적 인수 열거입니다. 두 번째 괄호에는 함수가 호출될 때 수행될 작업이 포함됩니다. 이 함수 정의가 유일한 것은 아니지만 우리는 이것을 사용할 것입니다(다른 정의는 공식 문서 에서 찾을 수 있습니다).


 with workDaysBetween(today, from)= ( with weekends = (Weeknum(today) - Weeknum(from)) * 2: HOURS_BETWEEN(from;today)/24 - weekends ):


사용자 정의 workDaysBetween 함수는 인수로 전달된 오늘 날짜와 다음 날짜 사이의 근무일을 계산합니다. 함수의 논리는 매우 간단합니다. 휴일 수를 세어 날짜 사이의 총 일수에서 뺍니다.


휴일 수를 계산하려면 오늘부터 오늘까지 몇 주가 지났는지 알아야 합니다. 이를 위해 각 주의 숫자 간의 차이를 계산합니다. 연초의 주 번호를 제공하는 Weeknum 함수에서 이 번호를 얻습니다. 이 차이에 2를 곱하면 지난 휴가 일수가 나옵니다.


다음으로, HOURS_BETWEEN 함수는 날짜 사이의 시간 수를 계산합니다. 결과를 24로 나누어 일수를 구하고, 이 숫자에서 휴일을 빼서 해당 날짜 사이의 근무일을 구합니다.


새로운 함수를 사용하여 여러 개의 보조 변수를 정의해 보겠습니다. 정의의 날짜 중 일부는 예제 시작 부분에서 설명한 전역 변수입니다.


 with daysAfterCreated = workDaysBetween(now,created): with daysAfterStart = workDaysBetween(now,latestTransitionToProgress): with daysAfterDone = workDaysBetween(now, resolutionDate):


코드를 읽기 쉽게 만들기 위해 조건의 결과를 저장하는 변수를 정의해 보겠습니다.


 with isWontDo = resolution = "Won't Do": with isRecentCreated = daysAfterCreated >= 0 and daysAfterCreated <= daysScope and not(resolution): with isRecentWork = daysAfterStart >= 0 and daysAfterStart <= daysScope : with isRecentDone = daysAfterDone >= 0 and daysAfterDone <= daysScope :


isRecentCreated 변수에 대해 선택적 조건과 not(해결책)을 추가했는데, 이는 작업이 이미 닫혀 있으면 최근 생성에 대한 정보에 관심이 없기 때문에 향후 줄을 단순화하는 데 도움이 됩니다.


최종 결과는 concat 함수를 통해 라인을 연결하여 구성됩니다.


 concat( if isRecentCreated : "*️⃣", if isRecentWork : "🚀", if isRecentDone : "✅", if isWontDo : "❌")


조건의 변수가 1과 같은 경우에만 이모티콘이 줄에 표시됩니다. 따라서 우리 줄은 작업에 대한 독립적인 변경 사항을 동시에 표시할 수 있습니다.


변경 사항이 있는 열의 최종 보기(왼쪽)


우리는 휴일 없이 근무일을 계산하는 주제를 다루었습니다. 이와 관련된 또 다른 문제가 있는데, 마지막 예제에서 이를 분석하고 동시에 배열에 대해 알아 보겠습니다.


휴무일을 제외한 근무시간 계산

최종 표시 예


문제

때때로 우리는 쉬는 날을 제외하고 작업이 얼마나 오랫동안 실행되었는지 알고 싶습니다. 예를 들어 이는 출시된 버전을 분석하는 데 필요합니다. 우리에게 휴가가 필요한 이유를 이해하기 위해. 단 하나는 월요일부터 목요일까지, 다른 하나는 금요일부터 월요일까지 운영되었습니다. 이러한 상황에서는 달력 날짜의 차이가 반대를 말하지만 작업이 동일하다고 말할 수는 없습니다.


불행하게도 "기본" 구조는 휴일을 무시하는 방법을 모르고 "상태 상태의 시간…" 옵션이 있는 필드는 토요일과 일요일이 휴일로 지정되어 있어도 Jira 설정에 관계없이 결과를 생성합니다.


결과적으로 우리의 목표는 휴일을 무시하고 정확한 근무일 수를 계산하고 이 시간에 대한 상태 전환의 영향을 고려하는 것입니다.


그리고 지위가 그것과 무슨 관련이 있습니까? 대답하겠습니다. 3월 10일부터 3월 20일 사이에 작업이 3일 동안 진행되었다고 계산했다고 가정해 보겠습니다. 그런데 이 3일 중에 하루는 휴지상태였고, 하루 반은 심사에 들어간 상태였습니다. 작업은 반나절 동안만 진행된 것으로 나타났습니다.


이전 예제의 솔루션은 상태 간 전환 문제로 인해 우리에게 적합하지 않습니다. 사용자 정의 workDaysBetween 함수는 선택한 두 날짜 사이의 시간만 고려하기 때문입니다.


제안 된 해결책

이 문제는 다양한 방법으로 해결될 수 있습니다. 이 예의 방법은 성능 측면에서 가장 비용이 많이 들지만 휴가 및 상태 계산 측면에서는 가장 정확합니다. 구현은 7.4(2021년 12월) 이전의 Structure 버전에서만 작동합니다.


따라서 공식의 아이디어는 다음과 같습니다.


  1. 작업 시작부터 완료까지 며칠이 지났는지 알아내야 합니다.
  2. 우리는 이것으로 배열을 만듭니다. 즉, 작업 시작과 끝 사이의 날짜 목록을 만듭니다.
  3. 목록에 휴일만 유지하세요.


모든 날짜에서 주말만 필터링(상태가 다를 수 있음)


  1. 이 휴일 중에는 작업이 "진행 중" 상태였던 날만 유지합니다(버전 7.4 "역사적 가치"의 기능이 여기서 도움이 될 것입니다).


'진행 중' 상태가 남아 있는 상태에서 불필요한 상태 제거


  1. 이제 목록에는 "진행 중" 기간과 일치하는 휴일만 있습니다.
  2. 별도로 우리는 "진행 중" 상태의 총 지속 시간을 알아냅니다(내장된 구조 옵션 "상태 지속 시간..."을 통해).
  3. 이 시간에서 이전에 얻은 휴가 일수를 뺍니다.


따라서 우리는 휴일과 추가 상태 간의 전환을 무시하고 작업에 대한 정확한 작업 시간을 얻을 것입니다.


사용된 구조 특징

  1. 변수 매핑
  2. Expr 언어 방법
  3. 지역 변수
  4. 정황
  5. 내부 메소드(자체 기능)
  6. 배열
  7. 작업 기록에 액세스
  8. 서식이 적용된 텍스트


코드 예시

 if defined(issueType) : if status != "Open" : with finishDate = if toQA != Undefined : toQA else if toDone != Undefined : toDone else now(): with startDate = DEFAULT(toProgress, toDone): with statusWeekendsCount(dates, status) = ( dates.filter(x -> weekday(x) > 5 and historical_value(this,"status",x)=status).size() ): with overallDays = round(hours_between(startDate,finishDate)/24): with sequenceArray = SEQUENCE(0,overallDays): with datesArray = sequenceArray.map(DATE_ADD(startDate,$,"day")): with progressWeekends = statusWeekendsCount(datesArray, "in Progress"): with progressDays = (timeInProgress/86400000 - progressWeekends).round(1): with color = if( progressDays = 0 ; "gray" ; progressDays > 0 and progressDays <= 2.5; "green" ; progressDays > 2.5 and progressDays <= 4; "orange" ; progressDays > 4; "red" ): """{color:$color}$progressDays d{color}"""


솔루션 분석


알고리즘을 코드로 전송하기 전에 구조 계산을 쉽게 해보겠습니다.


 if defined(issueType) : if status != "Open" :


해당 라인이 작업이 아니거나 상태가 "열림"인 경우 해당 라인을 건너뜁니다. 우리는 실행된 작업에만 관심이 있습니다.


날짜 사이의 일수를 계산하려면 먼저 FinishDate 및 startDate 날짜를 결정해야 합니다.


 with finishDate = if toQA != Undefined : toQA else if toDone != Undefined : toDone else now(): with startDate = DEFAULT(toProgress, toDone): 


작업의 논리적 종료를 나타내는 상태 식별


작업 완료 날짜(finishDate)는 다음과 같다고 가정합니다.

  • 작업이 "QA" 상태로 전환된 날짜
  • "폐쇄"로 전환되는 날짜
  • 또는 작업이 여전히 "진행 중"인 경우 오늘 날짜(얼마나 시간이 지났는지 이해하기 위해)


작업 시작 날짜 startDate는 "진행 중" 상태로 전환되는 날짜에 따라 결정됩니다. 작업중 단계로 넘어가지 않고 작업이 종료되는 경우가 있습니다. 이 경우 마감일을 시작일로 간주하므로 결과는 0일이 됩니다.


toQA에서 추측할 수 있듯이 toDone 및 toProgress는 첫 번째 및 이전 예제에서와 같이 적절한 상태에 매핑되어야 하는 변수입니다.


또한 새로운 DEFAULT(toProgress, toDone) 함수도 볼 수 있습니다. toProgress에 값이 있는지 확인하고 값이 없으면 toDone 변수의 값을 사용합니다.


다음은 statusWeekendsCount 사용자 정의 함수의 정의입니다. 날짜 목록과 밀접하게 관련되어 있으므로 나중에 다시 설명하겠습니다. 나중에 함수를 여기에 적용하는 방법을 이해할 수 있도록 이 목록의 정의로 바로 이동하는 것이 더 좋습니다.


우리는 [startDate(11.03이라고 가정), 12.03, 13.03, 14.03…finishDate] 형식의 날짜 목록을 얻고 싶습니다. Structure에서 모든 작업을 수행하는 간단한 함수는 없습니다. 이제 트릭을 사용해 보겠습니다.


  1. 0부터 근무 일수까지의 일련의 숫자, 즉 [0, 1, 2, 3 … n일 근무]로 간단한 목록을 만듭니다.
  2. 각 숫자(예: 날짜)에 작업 시작 날짜를 추가합니다. 결과적으로 필요한 유형의 목록(배열)을 얻습니다: [시작 + 0일, 시작 + 1일, 시작 + 2일 … 시작 + n일 작업].


시작 날짜부터 논리적 끝 날짜까지의 초기 날짜 배열 만들기


이제 코드에서 어떻게 구현하는지 살펴보겠습니다. 우리는 배열로 작업할 것입니다.


 with overallDays = round(hours_between(startDate,finishDate)/24): with sequenceArray = SEQUENCE(0,overallDays): with datesArray = sequenceArray.map(DATE_ADD(startDate,$,"day")):


작업을 수행하는 데 며칠이 걸릴지 계산합니다. 이전 예와 마찬가지로 24로 나누기와 hour_between(startDate,finishDate) 함수를 통해. 결과는overallDays변수에 기록됩니다.


시퀀스Array 변수의 형태로 숫자 시퀀스의 배열을 만듭니다. 이 배열은 SEQUENCE(0,overallDays) 함수를 통해 구성됩니다. 이 함수는 0부터 전체일까지의 시퀀스로 원하는 크기의 배열을 만듭니다.


다음은 마법입니다. 배열 함수 중 하나가 맵입니다. 배열의 각 요소에 지정된 작업을 적용합니다.


우리의 임무는 각 숫자(즉, 날짜의 숫자)에 시작 날짜를 추가하는 것입니다. DATE_ADD 함수는 이를 수행할 수 있으며 지정된 날짜에 특정 일, 월 또는 연도 수를 추가합니다.


이를 알고 문자열을 해독해 보겠습니다.


 with datesArray = sequenceArray.map(DATE_ADD(startDate, $,"day"))


SequenceArray의 각 요소에 .map() 함수는 DATE_ADD(startDate, $, “day”)를 적용합니다.


DATE_ADD에 대한 인수에 전달된 내용을 살펴보겠습니다. 첫 번째는 원하는 숫자가 추가될 날짜인 startDate입니다. 이 숫자는 두 번째 인수로 지정되지만 $가 표시됩니다.


$ 기호는 배열 요소를 나타냅니다. 구조는 DATE_ADD 함수가 배열에 적용되므로 $ 대신 원하는 배열 요소(즉, 0, 1, 2 …)가 있음을 이해합니다.


마지막 인수 “day”는 우리가 지정한 내용에 따라 함수가 일, 월, 연도를 추가할 수 있으므로 일을 추가한다는 표시입니다.


따라서 daysArray 변수는 작업 시작부터 완료까지의 날짜 배열을 저장합니다.


우리가 놓친 사용자 정의 기능으로 돌아가 보겠습니다. 추가 일수를 필터링하고 나머지를 계산합니다. 코드를 분석하기 전에 예제의 맨 처음 부분, 즉 휴가 및 상태 필터링에 대한 단락 3 및 4에서 이 알고리즘을 설명했습니다.


 with statusWeekendsCount(dates, status) = ( dates.filter(x -> weekday(x) > 5 and historical_value(this,"status",x)=status).size() ):


사용자 정의 함수에 두 개의 인수를 전달합니다. 날짜 배열(날짜라고 부르겠습니다)과 필수 상태(status)입니다. 전송된 날짜 배열에 .filter() 함수를 적용하여 필터 조건을 통과한 배열의 레코드만 유지합니다. 우리의 경우에는 두 가지가 있으며 and를 통해 결합됩니다. 필터 뒤에는 .size()가 표시되며, 모든 작업이 완료된 후 배열의 크기를 반환합니다.


표현식을 단순화하면 다음과 같은 결과가 나옵니다: array.filter(condition1 and Condition2).size(). 그래서 그 결과 우리에게 적합한 휴가일수, 즉 조건을 통과한 휴가일수를 얻게 되었습니다.


두 가지 조건을 자세히 살펴보겠습니다.


 x -> weekday(x) > 5 and historical_value(this,"status",x)=status


x -> 표현식은 필터 구문의 일부일 뿐이며 배열 x 의 요소를 호출함을 나타냅니다. 따라서 x는 각 조건에 나타납니다($의 경우와 유사). x는 전송된 날짜 배열의 각 날짜임이 밝혀졌습니다.


첫 번째 조건인 weekday(x) > 5에서는 날짜 x의 평일(즉, 각 요소)이 5보다 커야 합니다. 이는 토요일(6) 또는 일요일(7)입니다.


두 번째 조건은 Historical_value를 사용합니다.


 historical_value(this,"status",x) = status


이것이 Structure 7.4 버전의 특징입니다.


이 함수는 작업 기록에 액세스하고 지정된 필드에서 특정 날짜를 검색합니다. 이 경우 "상태" 필드에서 날짜 x를 검색하고 있습니다. 이 변수는 함수 구문의 일부일 뿐이며 자동으로 매핑되고 해당 줄의 현재 작업을 나타냅니다.


따라서 조건에서는 전송된 상태 인수와 배열의 각 날짜 x에 대해 Historical_value 함수에 의해 반환된 "상태" 필드를 비교합니다. 일치하면 해당 항목이 목록에 남아 있습니다.


마지막 터치는 원하는 상태의 일수를 계산하는 기능을 사용하는 것입니다.


 with progressWeekends = statusWeekendsCount(datesArray, "in Progress"): with progressDays = (timeInProgress/86400000 - progressWeekends).round(1):


먼저,dateArray에 "진행 중" 상태의 휴가 일수를 알아봅시다. 즉, 날짜 목록과 원하는 상태를 사용자 정의 함수 statusWeekendsCount에 전달합니다. 작업 상태가 "진행 중" 상태와 다른 모든 평일과 휴일을 모두 제거하고 남은 일수를 목록에 반환하는 함수입니다.


그런 다음 "Time in status..." 옵션을 통해 매핑하는 timeInProgress 변수에서 이 양을 뺍니다.


숫자 86400000은 밀리초를 일로 변환하는 제수입니다. .round(1) 함수는 결과를 10분의 1로 반올림하는 데 필요합니다(예: "4.1"). 그렇지 않으면 "4.0999999 …"와 같은 유형의 항목을 얻을 수 있습니다.


작업 기간을 표시하기 위해 색상 변수를 도입합니다. 작업에 소요된 일수에 따라 변경하겠습니다.


  • 회색 — 0일
  • 녹색 - 0일 초과 2.5일 미만
  • 빨간색 — 2.5~4일
  • 빨간색 — 4일 이상


 with color = if( progressDays = 0 ; "gray" ; progressDays > 0 and progressDays <= 2.5; "green" ; progressDays > 2.5 and progressDays <= 4; "orange" ; progressDays > 4; "red" ):


계산된 날짜의 결과가 포함된 마지막 줄은 다음과 같습니다.


 """{color:$color}$progressDays d{color}"""


결과는 아래 이미지와 같습니다.


근무 시간 필드의 최종 보기


그런데 동일한 수식으로 모든 상태의 시간을 표시할 수 있습니다. 예를 들어, "Pause" 상태를 사용자 정의 함수에 전달하고 "Time in ... — Pause"를 통해 timeInProgress 변수를 매핑하면 일시 중지된 정확한 시간을 계산합니다.


상태를 결합하여 “wip: 3.2d | rev: 12d”, 즉 작업 시간과 검토 시간을 계산합니다. 당신의 상상력과 작업 흐름에 의해서만 제한됩니다.


결론

우리는 비슷한 작업을 수행하거나 Jira 작업 분석을 위해 완전히 새롭고 흥미로운 것을 작성하는 데 도움이 되는 이 공식 언어의 다양한 기능을 제시했습니다.


이 기사가 공식을 이해하는 데 도움이 되었거나 적어도 이 주제에 관심을 갖게 되기를 바랍니다. 나는 "최고의 코드와 알고리즘"을 가지고 있다고 주장하지 않습니다. 따라서 예제를 개선할 수 있는 방법에 대한 아이디어가 있다면 공유해 주시면 감사하겠습니다!


물론 ALM Works 개발자보다 공식에 대해 더 잘 알려줄 사람은 없다는 점을 이해해야 합니다. 따라서 해당 문서와 웹 세미나에 대한 링크를 첨부합니다. 사용자 정의 필드 작업을 시작하는 경우 자주 확인하여 사용할 수 있는 다른 기능이 무엇인지 알아보십시오.