paint-brush
Formüller ve Yapıyla Zamandan ve Sinirlerden Tasarruf Edin Jira Eklentisiile@ipolubentcev
769 okumalar
769 okumalar

Formüller ve Yapıyla Zamandan ve Sinirlerden Tasarruf Edin Jira Eklentisi

ile Ivan Polubentsev36m2023/10/29
Read on Terminal Reader

Çok uzun; Okumak

Jira Structure eklentisine sahip formüller akıllara durgunluk verebilir: Tablolar oluştururken, görevlerle çalışmayı basitleştirirken ve sürümleri ve projeleri analiz ederken oyununuzu geliştirin.
featured image - Formüller ve Yapıyla Zamandan ve Sinirlerden Tasarruf Edin Jira Eklentisi
Ivan Polubentsev HackerNoon profile picture
0-item
1-item

Jira için Yapı eklentisi, görevler ve bunların analizi ile ilgili günlük çalışmalar için çok kullanışlıdır; Jira biletlerinin görselleştirilmesini ve yapılandırılmasını yeni bir seviyeye taşıyor ve bunu kutudan çıktığı gibi yapıyor.


Ve bunu herkes bilmese de Yapı formüllerinin işlevselliği aklınızı başınızdan alabilir. Formülleri kullanarak, görevlerle çalışmayı büyük ölçüde kolaylaştırabilecek son derece yararlı tablolar oluşturabilirsiniz ve en önemlisi, bunlar sürümlerin, destanların ve projelerin daha derin bir analizini gerçekleştirmek için faydalıdır.


Bir Burndown grafiği görüntülemeye veya bir biletin Sağlığını görevlerin bulunduğu bir tabloda göstermeye ne dersiniz?


Bu makalede, en basit örneklerden başlayarak karmaşık ama oldukça kullanışlı örneklere kadar kendi formüllerinizi nasıl oluşturacağınızı göreceksiniz.


Peki bu metin kimin için? ALM Works web sitesindeki resmi belgeler okuyucuların incelemesini beklerken neden bir makale yazıldığını merak edebilirsiniz. Bu doğru. Ancak ben, Structure'ın bu kadar geniş bir işlevselliği sakladığına dair en ufak bir fikri bile olmayan insanlardan biriyim: "Bir dakika, bu başından beri bir seçenek miydi?!" Bu farkındalık beni şunu düşündürdü: Formüller ve Yapılarla ne tür şeyler yapabileceklerini hâlâ bilmeyen başka insanlar da olabilir.


Bu makale aynı zamanda formüllere aşina olanlar için de faydalı olacaktır. Özel alanların kullanımına ilişkin bazı ilginç pratik seçenekler öğrenecek ve belki de bazılarını projeleriniz için ödünç alacaksınız. Bu arada, sizin de ilginç örnekleriniz varsa, bunları yorumlarda paylaşırsanız çok sevinirim. .


Her örnek, sorunun tanımından kodun açıklamasına kadar, soru kalmayacak şekilde yeterince detaylı bir şekilde analiz edilir. Elbette açıklamaların yanı sıra her örnek, analize dalmadan kendiniz deneyebileceğiniz kodlarla gösterilmiştir.


Okumak istemiyorsanız ancak formüllerle ilgileniyorsanız ALM Works web seminerlerine göz atın. Bunlar 40 dakikada temel bilgileri açıklıyor; bilgiler orada oldukça sıkıştırılmış bir şekilde sunulmaktadır.


Örnekleri anlamak için herhangi bir ek bilgiye ihtiyacınız yoktur, bu nedenle Jira ve Structure ile çalışmış olan herkes tablolarındaki örnekleri herhangi bir sorun yaşamadan tekrarlayabilecektir.


Geliştiriciler, Expr dilleriyle oldukça esnek bir sözdizimi sağladılar. Temel olarak buradaki felsefe “istediğin gibi yaz, işe yarayacaktır”.


Öyleyse başlayalım!


Neden formüllere ihtiyacımız var?

Peki neden formül kullanmak isteyelim ki? Bazen "Atanan", "Hikaye Puanları" vb. gibi standart Jira alanlarımızın yeterli olmadığı ortaya çıkıyor. Veya belirli alanlar için bir miktar hesaplamamız, kalan kapasiteyi versiyona göre görüntülememiz ve görevin kaç kez durumunun değiştiğini bulmamız gerekiyor. Belki de Yapımızın okunmasını kolaylaştırmak için birkaç alanı tek bir alanda birleştirmek istiyoruz.


Bu sorunları çözmek için formüllere ihtiyacımız var ve bunları özel alanlar oluşturmak için kullanacağız.


Yapmamız gereken ilk şey formülün nasıl çalıştığını anlamaktır. Bir diziye bir tür işlem uygulamamızı sağlar. Yapıya birçok görev yüklediğimiz için formül, tablonun tamamının her satırına uygulanır. Genellikle tüm operasyonları bu hatlardaki görevlerle çalışmayı amaçlamaktadır.


Dolayısıyla, formülden "Atanan" gibi bir Jira alanını görüntülemesini istersek, formül her göreve uygulanacak ve başka bir "Atanan" sütunumuz olacaktır.


Formüller birkaç temel öğeden oluşur:

  • Değişkenler — Jira alanlarına erişmek ve ara sonuçları kaydetmek için
  • Yerleşik işlevler — bunlar önceden tanımlanmış bir işlemi gerçekleştirir; örneğin tarihler arasındaki saat sayısını sayar veya bir dizideki verileri filtreler
  • Özel işlevler — benzersiz hesaplamalara ihtiyacımız varsa
  • Sonucun farklı görüntülenme biçimleri; örneğin, seçeneğiniz için "Tarih/Saat", "Süre", "Numara" veya "Wiki İşaretlemesi".


Formülleri tanımak

Bazı örnekler aracılığıyla formüllere ve sözdizimlerine daha aşina olacağız ve altı pratik durumu inceleyeceğiz.


Her örneğe bakmadan önce hangi Yapı özelliklerini kullandığımızı belirteceğiz; henüz açıklanmayan yeni özellikler kalın harflerle yazılacaktır. Aşağıdaki örneklerin her biri artan düzeyde karmaşıklığa sahip olacaktır. Bunlar, önemli formül özelliklerini size kademeli olarak tanıtmak amacıyla düzenlenmiştir.


Her seferinde göreceğiniz temel yapı şu şekildedir:

  • Sorun
  • Önerilen çözüm
  • Kullanılan Yapı özellikleri
  • Bir kod örneği
  • Çözümün analizi


Bu örnekler değişken eşlemeden karmaşık dizilere kadar çeşitli konuları kapsar:

  • Bir görevdeki çalışmanın başlangıç ve bitiş tarihlerini gösteren iki örnek (farklı ekrana sahip seçenekler)
  • Ana görev — ana görevin türünü ve adını görüntüler
  • Alt görevlerin Hikaye Puanlarının toplamı ve bu değerlendirmelerin durumu
  • Görev durumundaki son değişikliklerin bir göstergesi
  • İzin günleri (hafta sonları) ve ekstra durumlar hariç, çalışma süresinin hesaplanması


Formül oluşturma

Öncelikle formüllerle özel alanların nasıl oluşturulacağını bulalım. Yapının sağ üst kısmında, tüm sütunların sonunda bir “+” simgesi vardır; ona tıklayın. Görünen alana “Formül…” yazın ve uygun öğeyi seçin.


Formül oluşturma


Formülleri kaydetme

Bir formülü kaydetmeyi tartışalım. Ne yazık ki, belirli bir formülü ayrı bir yere (benim yaptığım gibi yalnızca not defterinize) kaydetmek hala mümkün değil. ALM Works web seminerinde ekip, bir formül bankası üzerinde çalıştıklarını ancak şimdilik bunları kaydetmenin tek yolunun formülle birlikte tüm görünümü kaydetmek olduğunu belirtti.


Bir formül üzerinde çalışmayı bitirdiğimizde, yapımızın görünümüne tıklamamız (büyük olasılıkla mavi yıldız işaretiyle işaretlenecektir) ve mevcut görünümün üzerine yazmak için "Kaydet"e tıklamamız gerekir. Veya yeni bir görünüm oluşturmak için “Farklı Kaydet…” seçeneğine tıklayabilirsiniz. (Yeni görünümler varsayılan olarak özel olduğundan diğer Jira kullanıcılarının kullanımına sunmayı unutmayın.)


Formül, belirli bir görünümdeki diğer alanlara kaydedilecektir ve bunu "Ayrıntıları Görüntüle" menüsünün "Gelişmiş" sekmesinde görebilirsiniz.


Sürüm 8.2'den başlayarak, Yapı artık formülleri 3 hızlı tıklamayla kaydetme olanağına sahip.

Kaydetme iletişim kutusuna formül düzenleme penceresinden ulaşılabilir. Bu pencere açık değilse, istediğiniz sütundaki üçgen ▼ simgesine tıklamanız yeterlidir.


Formülleri kaydetme


Düzenleme penceresinde “Kayıtlı Sütun” alanını görüyoruz, sağda mavi bildirimli bir simge var, bu da formüldeki değişikliklerin kaydedilmediği anlamına geliyor. Bu simgeye tıklayın ve “Farklı kaydet…” seçeneğini seçin.


Kaydedilen Sütun


Daha sonra sütunumuz (formül) için adları girin ve onu hangi alana kaydedeceğinizi seçin. Kişisel bir listeye kaydetmek istiyorsak “Sütunlarım”. "Global", böylece formül, Yapınızdaki tüm kullanıcılar tarafından düzenlenebilecek genel listeye kaydedilir. “Kaydet”e tıklayın.


Kaydet'i tıklayın


Artık formülümüz kaydedildi. Herhangi bir yapıya yükleyebilir veya herhangi bir yerden yeniden kaydedebiliriz. Formül yeniden kaydedilerek kullanıldığı tüm yapılarda güncellenecektir.


Değişken eşleme de formülle birlikte kaydedilir, ancak eşleme hakkında daha sonra konuşacağız.


Şimdi örneklerimize geçelim!


Bir görevdeki çalışmanın başlangıç ve bitiş tarihlerini görüntüleme

Son iki sütundaki özel tarihler

Sorun

Görev listesinin yanı sıra bu görevler üzerinde çalışmanın başlangıç ve bitiş tarihlerini içeren bir tabloya ihtiyacımız var. Ayrıca tabloyu ayrı bir excel-gantt'a aktarmak için de ihtiyacımız var. Ne yazık ki Jira ve Structure bu tür tarihleri nasıl hazırlayacaklarını bilmiyor.

Önerilen çözüm

Başlangıç ve bitiş tarihleri belirli durumlara geçiş tarihleridir, bizim durumumuzda bunlar “Devam Ediyor” ve “Kapalı”dır. Bu tarihleri almamız ve her birini ayrı bir alanda göstermemiz gerekiyor (bu, gantt'a daha fazla aktarım için gereklidir). Yani iki alanımız olacak (iki formül).


Kullanılan Yapı özellikleri

  1. Değişken eşleme
  2. Görüntü formatını ayarlama yeteneği


Bir kod örneği

Başlangıç tarihi alanı:

 firstTransitionToStart


Bitiş tarihi alanı:

 latestTransitionToDone


Çözümün analizi

Bu durumda kod, başlangıç tarihi alanı için FirstTransitionToStart ve ikinci alan için lastTransitionToDone olmak üzere tek bir değişkendir.


Şimdilik başlangıç tarihi alanına odaklanalım. Amacımız, görevin "Devam Ediyor" durumuna geçtiği tarihi elde etmektir (bu, görevin mantıksal başlangıcına karşılık gelir), bu nedenle değişken, daha sonra tahmin etme ihtiyacını önlemek için oldukça açık bir şekilde "devam ediyor" durumuna "ilk geçiş" olarak adlandırılır. başlangıç".


Tarihi bir değişkene dönüştürmek için değişken eşlemeye yöneliriz. “Kaydet” butonuna tıklayarak formülümüzü kaydedelim.


Formülü kaydetmek için tıklayın


Değişkenimiz “Değişkenler” bölümünde yanında ünlem işaretiyle göründü. Yapı, bir değişkeni Jira'daki bir alana bağlayamayacağını ve bunu kendimiz yapmamız (yani haritalandırmamız) gerektiğini belirtir.


Değişkene tıklayın ve haritalama arayüzüne gidin. Alanı veya gerekli işlemi seçin — “Geçiş Tarihi…” işlemini arayın. Bunun için seçim alanına “geçiş” yazın. Size aynı anda birden fazla seçenek sunulacak ve bunlardan biri bize uygun: “Devam Ediyor'a İlk Geçiş”. Ancak haritalamanın nasıl çalıştığını göstermek için “Geçiş Tarihi…” seçeneğini seçelim.


Eşleme yapılandırması


Bundan sonra, geçişin gerçekleştiği durumu ve bu geçişin sırasını (ilk veya son) seçmeniz gerekir.


Bir görev üzerinde çalışmanın başlangıcı ilk geçiş olduğundan, "Durum" - "Durum: Devam Ediyor" (veya İş Akışınızda ilgili durum) ve "Geçiş" - "Duruma ilk geçiş" seçeneklerini seçin veya girin. karşılık gelen duruma.


İstediğiniz kategoriyi seçin



"Geçiş Tarihi..." yerine başlangıçta önerilen "İlk Geçiş Devam Ediyor" seçeneğini seçseydik, sonuç hemen hemen aynı olurdu - Yapı bizim için gerekli parametreleri seçerdi. Tek şey, "Durum: Devam Ediyor" yerine "Kategori: Devam Ediyor" olacaktır.


Durum kategorisi ile durum arasındaki fark


Önemli bir özelliğe değineyim: Durum ve kategori iki farklı şeydir. Durum belirli bir durumdur ve açıktır, ancak bir kategori birden fazla durumu içerebilir. Yalnızca üç kategori vardır: "Yapılacaklar", "Devam Ediyor" ve "Bitti". Jira'da genellikle sırasıyla gri, mavi ve yeşil renklerle işaretlenirler. Durum bu kategorilerden birine ait olmalıdır.

Aynı kategorideki durumlarla karışıklığı önlemek için bu gibi durumlarda belirli bir durumu belirtmenizi öneririm. Örneğin, projede "Yapılacaklar" kategorisinde "Açık" ve "QA Kuyruğu" olmak üzere iki durumumuz var.


Örneğimize geri dönelim.


Gerekli seçenekleri seçtikten sonra “< Değişkenler Listesine Dön” butonuna tıklayarak ilkTransitionToStart değişkeni için eşleştirme seçeneklerini tamamlayabiliriz. Her şeyi doğru yaparsak yeşil bir onay işareti göreceğiz.


Genel, varsayılan değeri gösterir (milisaniye cinsinden)


Aynı zamanda özel alanımızda hiç tarihe benzemeyen bazı tuhaf sayılar görüyoruz. Bizim durumumuzda formülün sonucu, FirstTransitionToStart değişkeninin değeri olacaktır ve değeri Ocak 1970'ten bu yana milisaniyedir. Doğru tarihi elde etmek için belirli bir formül görüntüleme formatı seçmemiz gerekir.


Format seçimi düzenleme penceresinin en altında bulunur. Burada varsayılan olarak “Genel” seçilidir. Tarihin doğru görüntülenmesi için “Tarih / Saat”e ihtiyacımız var.


Genel yerine Tarih/Saat'i seçin


İkinci alan olan lastTransitionToDone için de aynısını yapacağız. Tek fark, haritalama sırasında durumu değil, zaten "Bitti" kategorisini seçebiliyor olmamızdır (çünkü genellikle tek bir net görev tamamlama durumu vardır). “Bitti” kategorisine en son geçişle ilgilendiğimiz için geçiş parametresi olarak “En Son Geçiş”i seçiyoruz.


İki alan için nihai sonuç şu şekilde görünecektir.


Tarihlerle birlikte son görünüm


Şimdi aynı sonucu kendi görüntüleme formatımızla nasıl elde edeceğimizi görelim.


Kendi formatımızla tarih gösterimi

Özel biçim örneği


Sorun

Gantt tablosu için özel bir formata ihtiyacımız olduğundan önceki örnekteki tarih görüntüleme formatından memnun değiliz — “01.01.2022”.


Önerilen çözüm

Bize uygun formatı belirterek Yapının yerleşik işlevlerini kullanarak tarihleri görüntüleyelim.


Kullanılan yapı özellikleri

  1. Değişken eşleme
  2. İfade işlevleri


Bir kod örneği

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


Çözümün analizi

Geliştiriciler, tarihi kendi formatımızda görüntülemek için ayrı bir işlev de dahil olmak üzere birçok farklı işlev sağladı: FORMAT_DATETIME; kullanacağımız şey bu. İşlev iki bağımsız değişken kullanır: bir tarih ve istenen formatta bir dize.


Önceki örnektekiyle aynı eşleme kurallarını kullanarak ilkTransitionToStart değişkenini (ilk argüman) ayarladık. İkinci argüman ise formatı belirten bir string ve biz bunu şu şekilde tanımlıyoruz: “dd.MM.yyyy”. Bu bizim istediğimiz “01.01.2022” formuna karşılık geliyor.


Böylece formülümüz anında istenilen biçimde sonuç verecektir. Böylece saha ayarlarında “Genel” seçeneğini tutabiliyoruz.


İşin bitiş tarihinin yer aldığı ikinci alan da aynı şekilde yapılır. Sonuç olarak yapı aşağıdaki resimdeki gibi görünmelidir.


Dönüşümden sonraki son besleme


Prensip olarak formül söz dizimi ile çalışırken önemli bir zorluk yoktur. Bir değişkene ihtiyacınız varsa adını yazın; eğer bir fonksiyona ihtiyacınız varsa, yine sadece ismini yazın ve argümanları (gerekliyse) iletin.


Structure bilinmeyen bir isimle karşılaştığında, bunun bir değişken olduğunu varsayar ve kendisini haritalamaya çalışır veya bizden yardım ister.


Bu arada, önemli bir not: Yapı büyük/küçük harfe duyarlı değildir, bu nedenle FirstTransitionToStart, Firsttransitiontostart ve firSttrAnsItiontOStarT aynı değişkenlerdir. Aynı kural işlevler için de geçerlidir. Belirgin bir kod stili elde etmek için örneklerde MSDN'nin Büyük Harf Kullanımı Kurallarının kurallarına uymaya çalışacağız.


Şimdi sözdizimini inceleyelim ve sonucu görüntülemek için özel bir formata bakalım.


Ana görevin adının görüntülenmesi

Ebeveynin adı Özetten önce görüntülenir


Sorun

Normal görevlerle (Görev, Hata vb.) ve alt görevleri olan Hikaye türü görevlerle çalışıyoruz. Bir noktada çalışanın belirli bir süre boyunca hangi görev ve alt görevler üzerinde çalıştığını bulmamız gerekiyor.


Sorun şu ki, birçok alt görev hikayenin kendisi hakkında bilgi vermiyor; bunlara "hikaye üzerinde çalışmak", "ayarlamak" veya örneğin "efekti etkinleştirmek" deniyor. Ve belirli bir süre için bir görev listesi talep edersek, başka hiçbir yararlı bilgi olmadan "hikaye üzerinde çalışmak" adı verilen bir düzine görev alacağız.


İki sütuna bölünmüş bir listeye sahip olmak istiyoruz: bir görev ve bir ana görev, böylece gelecekte böyle bir listeyi çalışanlara göre gruplandırmak mümkün olacaktır.


Önerilen çözüm

Projemizde, bir görevin bir ebeveyni olabileceği durumlarda iki seçeneğimiz var:

  1. Görev bir alt görevdir ve üst öğesi yalnızca Hikayedir
  2. Bir görev normal bir görevdir (Görev, Hata vb.) ve Epic'e sahip olabilir veya olmayabilir; bu durumda görevin hiçbir üst öğesi yoktur.


Yani şunları yapmalıyız:

  1. Bir görevin bir üst öğesi olup olmadığını öğrenin
  2. Bu ebeveynin türünü öğrenin
  3. Bu görevin türünü ve adını aşağıdaki şemaya göre hesaplayın: “[Ebeveyn-tipi] Ebeveyn-adı”.


Bilginin algılanmasını kolaylaştırmak için görev türünün metnini renklendireceğiz: yani "[Hikaye]" veya "[Epik]".


Ne kullanacağız:

  1. Değişken eşleme
  2. Durum
  3. Görev alanlarına erişim
  4. Görüntüleme formatı — wiki işaretlemesi


Bir kod örneği

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


Çözümün analizi

Yalnızca bir dize çıktısı alıp görev türünü ve adını buraya eklememiz gerekiyorsa formül neden bir if koşuluyla başlıyor? Görev alanlarına erişmenin evrensel bir yolu yok mu? Evet ama görevler ve destanlar için bu alanlar farklı isimlendiriliyor ve bunlara da farklı şekilde erişmeniz gerekiyor, bu Jira'nın bir özelliği.


Farklılıklar ebeveyn arama düzeyinde başlar. Bir alt görev için ebeveyn, "Ebeveyn Sorunu" Jira alanında yaşar ve normal bir görev için destan, "Epik Bağlantı" alanında bulunan ebeveyn olacaktır. Buna göre bu alanlara erişim için iki farklı seçenek yazmamız gerekecek.


Burası if koşuluna ihtiyacımız olan yer. Expr dilinin koşullarla başa çıkmanın farklı yolları vardır. Aralarında seçim bir zevk meselesidir.


“Excel benzeri” bir yöntem var:

 if (condition1; result1; condition2; result2 … )


Veya daha "kod benzeri" bir yöntem:

 if condition1 : result1 else if condition2 : result2 else result3


Örnekte ilk seçeneği kullandım; şimdi kodumuza basitleştirilmiş bir şekilde bakalım:

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


İki bariz durum görüyoruz:

  • Parent.Issuetype = “Hikaye”
  • EpicLink


Gelin ne yaptıklarını bulalım ve ilki olan Parent.Issuetype=”Story” ile başlayalım.


Bu durumda Ana, “Ana Sorun” alanına otomatik olarak eşlenen bir değişkendir. Yukarıda tartıştığımız gibi alt görevin ebeveyninin yaşaması gereken yer burasıdır. Nokta gösterimini (.) kullanarak bu ebeveynin özelliğine, özellikle de “Sorun Türü” Jira alanına karşılık gelen Issuetype özelliğine erişiriz. Parent.Issuetype satırının tamamının, eğer böyle bir görev mevcutsa, bize ana görevin türünü döndürdüğü ortaya çıktı.


Ayrıca geliştiriciler zaten bizim için ellerinden gelenin en iyisini yaptığından hiçbir şeyi tanımlamamıza veya haritalandırmamıza gerek yoktu. Örneğin burada, dilde önceden tanımlanmış tüm özelliklere (Jira alanları dahil) bir bağlantı bulunur ve burada, ek ayarlara gerek kalmadan güvenle erişilebilen tüm standart değişkenlerin bir listesini görebilirsiniz.


Bu nedenle ilk koşul, ana görevin türünün Hikaye olup olmadığına bakmaktır. İlk koşul karşılanmazsa üst görevin türü Hikaye değildir veya hiç mevcut değildir. Bu da bizi ikinci duruma getiriyor: EpicLink.


Aslında bu, “Epic Link” Jira alanının dolu olup olmadığını kontrol ettiğimiz zamandır (yani varlığını kontrol ediyoruz). EpicLink değişkeni de standarttır ve eşlenmesine gerek yoktur. Görevin Epic Link'e sahip olması durumunda koşulumuzun karşılandığı ortaya çıktı.


Üçüncü seçenek ise koşullardan hiçbirinin karşılanmadığı durumdur, yani görevin ne bir ebeveyni ne de Epic Linki vardır. Bu durumda hiçbir şey göstermiyoruz ve alanı boş bırakıyoruz. Hiçbir sonuç alamadığımız için bu otomatik olarak yapılır.


Koşulları çözdük, şimdi sonuçlara geçelim. Her iki durumda da metin ve özel biçimlendirme içeren bir dizedir.


Sonuç 1 (ebeveyn Hikaye ise):

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


Sonuç 2 (Epic Link varsa):

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


Her iki sonuç da yapı bakımından benzerdir: her ikisi de çıktı dizesinin başında ve sonunda bulunan üçlü tırnaklardan """, açılış {renk: COLOR} ve kapanış {renk} bloklarındaki renk belirtiminden ve aynı zamanda çıkış dizesi aracılığıyla yapılan işlemlerden oluşur. $ sembolü. Üçlü tırnak, yapıya içeride değişkenler, işlemler veya biçimlendirme blokları (renkler gibi) olacağını söyler.


İlk koşulun sonucu için:

  1. ${Parent.Issuetype} üst görevinin türünü aktarın
  2. Köşeli parantez içine alın “[…]”
  3. Her şeyi yeşil renkle vurgulayın ve bu ifadeyi [${Parent.Issuetype}], "yeşil" yazdığımız {color:green}…{color} renk seçim bloğuna sarın.
  4. Ve son bir şey olarak, ana görevin adını ${Parent.Summary} boşluğuyla ayırarak ekleyin.


Böylece “[Hikaye] Bazı görev adları” dizesini elde ederiz. Tahmin edebileceğiniz gibi Özet aynı zamanda standart bir değişkendir. Bu tür dizeleri oluşturma şemasını daha net hale getirmek için resmi belgelerden bir görsel paylaşmama izin verin.


Resmi belgelerden özel satır şeması


Benzer şekilde ikinci sonuç için dizeyi topluyoruz ancak rengi hex kodu aracılığıyla ayarlıyoruz. Destanın renginin “#713A82” olduğunu anladım (bu arada yorumlarda Epic için daha doğru bir renk önerebilirsiniz). Epic için değişen alanları (özellikleri) unutmayın. “Özet” yerine “EpicName” kullanın, “Ebeveyn” yerine “EpicLink” kullanın.


Sonuç olarak formülümüzün şeması bir koşullar tablosu olarak temsil edilebilir.


Durum: Ebeveyn görevi mevcut ve türü Hikaye.

Sonuç: Yeşil türde ebeveyn görevi ve adını içeren satır.

Durum: Epic Link alanı doldurulmuştur.

Sonuç: Türün epik rengini ve adını içeren çizgi.


Varsayılan olarak alanda “Genel” görüntüleme seçeneği seçili olup, bunu değiştirmezseniz, renk değişmeden ve bloklar tanımlanmadan sonuç düz metin gibi görünecektir. Görüntüleme biçimini "Wiki İşaretlemesi" olarak değiştirirseniz metin dönüştürülecektir.


1) Genel Görüntüleniyor - varsayılan olarak düz metni olduğu gibi gösterir 2) Genel'i Wiki İşaretlemesi ile değiştirin



Şimdi Jira alanlarıyla ilgili olmayan değişkenleri, yani yerel değişkenleri tanıyalım.


Renk göstergesi ile Hikaye puanı miktarının hesaplanması

Hikaye puanı toplamları farklı renklerle vurgulanır


Sorun

Önceki örnekten, alt görevleri olan Hikaye türündeki görevlerle çalıştığımızı öğrendiniz. Bu, tahminlerde özel bir duruma yol açmaktadır. Bir Hikaye puanı elde etmek için, soyut Hikaye puanları olarak tahmin edilen alt görevlerinin puanlarını özetliyoruz.


Yaklaşım alışılmadık ama bizim için işe yarıyor. Yani, Hikayenin bir tahmini olmadığı halde alt görevlerin bir tahmini olduğunda sorun yoktur, ancak hem Hikayenin hem de alt görevlerin bir tahmini olduğunda, Yapıdan standart seçenek olan “Σ Hikaye Noktaları” yanlış çalışır.


Bunun nedeni Story tahmininin alt görevlerin toplamına eklenmesidir. Sonuç olarak Story'de yanlış miktar görüntüleniyor. Bundan kaçınmak ve Story'de belirlenen tahminle ve alt görevlerin toplamıyla tutarsızlık belirtisi eklemek istiyoruz.


Önerilen çözüm

Tahminin Story'de ayarlanıp ayarlanmayacağına bağlı olduğundan birkaç koşula ihtiyacımız var.


Yani koşullar:


Story'de herhangi bir tahmin olmadığında , bu değerin henüz Story'de ayarlanmadığını belirtmek için alt görevlerin toplam tahminini turuncu renkte görüntüleriz


Story'nin bir tahmini varsa , bunun alt görevlerin toplamı tahminiyle eşleşip eşleşmediğini kontrol edin:

  • Eşleşmiyorsa, tahmini kırmızı renkle renklendirin ve doğru tutarı yanına parantez içinde yazın.
  • Bir tahmin ve toplam eşleşiyorsa, yeşil renkle bir tahmin yazın


Bu koşulların ifadesi kafa karıştırıcı olabilir, o yüzden bunları bir şema halinde ifade edelim.


Metin görüntüleme seçeneğini seçmek için algoritma


Kullanılan yapı özellikleri

  1. Değişken eşleme
  2. Yerel değişkenler
  3. Toplama yöntemleri
  4. Koşullar
  5. Biçimlendirmeli metin


Bir kod örneği

 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}"""


Çözümün analizi

Kodun derinliklerine dalmadan önce, hangi değişkenlere ihtiyacımız olduğunu anlamak için şemamızı daha "kod benzeri" bir yola dönüştürelim.


Değişkenlerle yeniden yazılan aynı algoritma


Bu şemadan ihtiyacımız olacağını görüyoruz:


Durum değişkenleri:

  • isEstimated (tahminin kullanılabilirliği)
  • isError (Hikaye tahmininin ve toplamın yazışması)


Metin renginin bir değişkeni — renk


Tahminin iki değişkeni:

  • toplam (Alt görevler tahmininin toplamı)
  • sp (Hikaye puanları)


Ayrıca, renk değişkeni ayrıca bir dizi koşula da bağlıdır; örneğin bir tahminin kullanılabilirliği ve satırdaki görevin türü (aşağıdaki şemaya bakın).


Renk seçimi için algoritma


Bu nedenle, rengi belirlemek için görev türünün Story olup olmadığını belirten başka bir koşul değişkenine, isStory'ye ihtiyacımız olacak.


sp değişkeni (hikaye noktaları) standart olacak, yani otomatik olarak uygun Jira alanına eşleşecek. Geri kalan değişkenleri kendimiz tanımlamalıyız ve bunlar bizim için yerel olacaktır.


Şimdi şemaları kodda uygulamaya çalışalım. Öncelikle tüm değişkenleri tanımlayalım.


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


Satırlar aynı sözdizimi şemasıyla birleştirilmiştir: with anahtar sözcüğü, değişken adı ve satırın sonundaki iki nokta üst üste simgesi “:”.


Bildirim yerel değişkenleri için sözdizimi


With anahtar sözcüğü yerel değişkenleri (ve özel işlevleri, ancak bunun hakkında daha fazlasını ayrı bir örnekte) belirtmek için kullanılır. Formüle, bir sonraki adımda eşlenmesi gerekmeyen bir değişkenin geleceğini söyler. İki nokta üst üste “:” değişken tanımının sonunu işaretler.


Böylece isEstimated değişkenini oluşturuyoruz (bu durumun önemli olmadığını hatırlatmak isteriz). Hikaye puanları alanının dolu olup olmamasına bağlı olarak 1 veya 0'ı saklayacağız. Storypoints değişkeni otomatik olarak eşlenir çünkü daha önce aynı isimde bir yerel değişken oluşturmadık (örneğin, storypoints = … :) ile.


Tanımsız değişken bir şeyin yokluğunu ifade eder (diğer dillerde null, NaN ve benzeri gibi). Bu nedenle hikaye noktaları != tanımsız ifadesi şu soru gibi okunabilir: “Hikaye puanları alanı doldurulmuş mu?”.


Daha sonra tüm alt görevlerin hikaye noktalarının toplamını belirlemeliyiz. Bunu yapmak için yerel bir değişken yaratıyoruz: ChildrenSum.


 with childrenSum = sum#children{storypoints}:


Bu toplam, toplama işlevi aracılığıyla hesaplanır. (Bunun gibi işlevler hakkında resmi belgelerden bilgi edinebilirsiniz.) Özetle, Yapı, mevcut görünümün hiyerarşisini dikkate alarak çeşitli işlemleri görevlerle gerçekleştirebilir.


Toplama fonksiyonunu kullanıyoruz ve buna ek olarak “#” sembolünü kullanarak, toplamın hesaplanmasını yalnızca mevcut satırın herhangi bir alt göreviyle sınırlayan açıklama çocuklarını geçiyoruz. Kıvrımlı parantez içinde hangi alanı özetlemek istediğimizi belirtiyoruz; hikaye noktaları cinsinden bir tahmine ihtiyacımız var.


Bir sonraki yerel değişken olan isStory, bir koşulu saklar: geçerli satırdaki görev türünün Hikaye olup olmadığı.


 with isStory = issueType = "Story":


Önceki örnekten tanıdık olan issueType değişkenine, yani istenen alanı kendisi ile eşleştiren görev türüne dönüyoruz. Bunu yapıyoruz çünkü bu standart bir değişken ve daha önce onu tanımlamadık.


Şimdi isErr değişkenini tanımlayalım; bu, alt görev toplamı ile Hikaye tahmini arasında bir tutarsızlığa işaret eder.


 with isErr = isStory AND childrenSum != storypoints:


Burada daha önce oluşturduğumuz isStory ve ChildrenSum yerel değişkenlerini kullanıyoruz. Bir hata sinyali vermek için iki koşulun aynı anda karşılanması gerekir: sorun türü Hikayedir (isStory) ve (AND) alt puanların toplamı (childrenSum), görevdeki belirlenen tahmine (storypoints) eşit değildir (!=) ). Tıpkı JQL'de olduğu gibi, koşulları oluştururken AND veya OR gibi bağlantı sözcüklerini kullanabiliriz.


Yerel değişkenlerin her biri için satırın sonunda bir “:” sembolü bulunduğunu unutmayın. Değişkeni tanımlayan tüm işlemlerden sonra en sonunda olmalıdır. Örneğin, bir değişkenin tanımını birkaç satıra bölmemiz gerekiyorsa, iki nokta üst üste “:” yalnızca son işlemden sonra yerleştirilir. Örnekte olduğu gibi renk değişkeni — metnin rengi.


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


Burada çok sayıda “:” görüyoruz, ancak farklı roller oynuyorlar. if isStory'den sonraki iki nokta üst üste isStory koşulunun sonucudur. Yapıyı hatırlayalım: if koşul : sonuç. Bir değişkeni tanımlayan bu yapıyı daha karmaşık bir biçimde sunalım.


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


Eğer koşul2 : sonuç2 değilse sonuç3'ün, ilk koşulun sonucu olduğu ve en sonunda değişkenin tanımını tamamlayan iki nokta üst üste ":" olduğu ortaya çıktı.


İlk bakışta rengin tanımı karmaşık görünebilir, ancak aslında burada örneğin başında sunulan renk tanımı şemasını anlattık. Sadece ilk koşulun sonucu olarak başka bir koşul başlıyor; iç içe geçmiş bir durum ve onun içinde başka bir durum.


Ancak nihai sonuç, daha önce sunulan şemadan biraz farklıdır.


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


Şemada olduğu gibi kodda iki kez “{color}$sp'' yazmamıza gerek yok; bazı konularda daha akıllı olacağız. Dalda, eğer görevin bir tahmini varsa, her zaman {color: $color}$storypoints{color} (yani sadece gerekli renkteki hikaye noktalarına ilişkin bir tahmin) görüntüleriz ve eğer bir hata varsa o zaman Bir boşluktan sonra satırı alt görev tahmininin toplamı ile tamamlayacağız: ($childrenSum).


Hata yoksa eklenmeyecektir. Ayrıca değişken tanımlamadığımız, nihai sonucu bir koşul üzerinden gösterdiğimiz için “:” simgesinin bulunmadığına da dikkatinizi çekerim.


Aşağıdaki görseldeki çalışmamızı “∑SP (mod)” alanında değerlendirebiliriz. Ekran görüntüsünde özellikle iki ek alan gösterilmektedir:


  • “Hikaye Puanları” — hikaye puanlarındaki bir tahmin (standart Jira alanı).
  • “∑ Hikaye Puanları” — miktarı yanlış hesaplayan Yapı standardı özel alanı.


Alanın son görünümü ve standart Hikaye Puanı ve ∑ Hikaye Puanı alanlarıyla karşılaştırılması


Bu örneklerin yardımıyla, çoğu sorunu çözmenize yardımcı olacak yapı dilinin temel özelliklerini analiz ettik. Şimdi iki kullanışlı özelliğe daha bakalım: fonksiyonlarımız ve dizilerimiz. Kendi özel fonksiyonumuzu nasıl oluşturacağımızı göreceğiz.


Son değişiklikler

Soldaki emojiye dikkat edin; özel bir alanı temsil eder


Sorun

Bazen bir sprintte çok sayıda görev vardır ve bunlardaki küçük değişiklikleri kaçırabiliriz. Örneğin yeni bir alt görevi veya hikayelerden birinin bir sonraki aşamaya geçtiğini kaçırabiliriz. Görevlerdeki en son önemli değişiklikleri bize bildiren bir araca sahip olmak güzel olurdu.


Önerilen çözüm

Dünden bu yana meydana gelen üç tür görev durumu değişikliğiyle ilgileniyoruz: görev üzerinde çalışmaya başladık, yeni bir görev ortaya çıktı, görev kapatıldı. Ayrıca görevin “Yapılmayacak” kararıyla kapatıldığını görmek faydalı olacaktır.


Bunu yapmak için en son değişikliklerden sorumlu bir dizi emojinin bulunduğu bir alan oluşturacağız. Örneğin, dün bir görev oluşturulmuşsa ve üzerinde çalışmaya başlamışsak, o zaman iki emojiyle işaretlenecektir: "Devam ediyor" ve "Yeni görev".


Örneğin "Devam Ediyor" durumuna geçiş tarihi veya ayrı bir "Çözüm" alanı gibi birkaç ek alan görüntülenebiliyorsa neden böyle bir özel alana ihtiyacımız var? Cevap basit; insanlar emojileri farklı alanlarda yer alan ve analiz edilmesi gereken metinlere göre daha kolay ve hızlı algılıyorlar. Formül her şeyi tek bir yerde toplayacak ve bizim için analiz edecek, bu da bize daha faydalı şeyler için çaba ve zaman kazandıracak.


Farklı emojilerin neyden sorumlu olacağını belirleyelim:

  • *️⃣ yeni bir görevi işaretlemenin en yaygın yoludur
  • ✅ tamamlanmış bir görevi işaretler
  • ❌ iptal etmeye karar verdiğiniz bir görevi belirtir (“Yapmayacağım”)
  • 🚀 görev üzerinde çalışmaya başlamaya karar verdiğimiz anlamına gelir (bu emoji ekibimiz için uygundur, sizin için farklı olabilir)


Kullanılan yapı özellikleri

  1. Değişken eşleme
  2. Expr dil yöntemleri
  3. Yerel değişkenler
  4. Koşullar
  5. Kendi fonksiyonumuz


Bir kod örneği

 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 : "❌")

Çözümün analizi


Öncelikle bizi ilgilendiren olayları belirlemek için ihtiyacımız olan küresel değişkenleri düşünelim. Dünden bu yana şunu bilmemiz gerekiyor:

  • Görev oluşturuldu
  • Durum “Devam Ediyor” olarak değiştirildi
  • Bir çözüm bulundu (ve hangisi)


Yeni eşleme değişkenlerinin yanı sıra mevcut değişkenleri kullanmak tüm bu koşulları kontrol etmemize yardımcı olacaktır.

  • oluşturuldu — görevin oluşturulma tarihi
  • en sonTransitionToProgress — “Devam Ediyor” durumuna geçişin en son tarihi (bunu önceki örnekte olduğu gibi eşliyoruz)
  • çözünürlükDate — görevin tamamlanma tarihi
  • çözünürlük — çözünürlük metni


Hadi koda geçelim. İlk satır, görev türünün mevcut olup olmadığını kontrol eden bir koşulla başlar.


 if defined(issueType):


Bu, belirtilen alanın varlığını kontrol eden yerleşik tanımlı işlev aracılığıyla yapılır. Kontrol, formülün hesaplanmasını optimize etmek için yapılır.


Eğer çizgi bir görev değilse, Yapı'ya gereksiz hesaplamalar yüklemeyeceğiz. Görünüşe göre if'ten sonraki tüm kodlar sonuç, yani if (koşul : sonuç) yapısının ikinci kısmı. Ve eğer koşul karşılanmazsa kod da çalışmaz.


Hesaplamaları optimize etmek için now = now(): içeren bir sonraki satıra da ihtiyaç vardır. Kodun ilerleyen kısımlarında, farklı tarihleri geçerli tarihle birkaç kez karşılaştırmamız gerekecek. Aynı hesaplamayı defalarca yapmamak adına bu tarihi bir defa hesaplayıp artık local değişken haline getireceğiz.


“Dünümüzü” ayrı tutmak da güzel olurdu. Uygun "dün" ampirik olarak 1,3 güne dönüştü. Bunu bir değişkene dönüştürelim: günlerScope = 1.3: ile.


Şimdi iki tarih arasındaki gün sayısını birkaç kez hesaplamamız gerekiyor. Örneğin, geçerli tarih ile işin başlangıç tarihi arasında. Elbette yerleşik bir DAYS_BETWEEN fonksiyonu var ki bu da bize uygun gibi görünüyor. Ancak, örneğin görev Cuma günü oluşturulduysa, o zaman Pazartesi günü yeni bir görev bildirimi görmeyeceğiz, çünkü aslında 1,3 günden fazla zaman geçti. Ayrıca DAYS_BETWEEN fonksiyonu sadece toplam gün sayısını sayıyor (yani 0,5 gün 0 güne dönüşecek), bu da bize yakışmıyor.


Bir gereklilik oluşturduk; bu tarihler arasındaki iş günlerinin tam sayısını hesaplamamız gerekiyor; ve özel bir işlev bu konuda bize yardımcı olacaktır.


Yerel bildirim işlevlerinin sözdizimi


Tanımlayıcı sözdizimi, yerel bir değişkeni tanımlamak için kullanılan sözdizimine çok benzer. Tek fark ve tek ekleme, ilk parantez içindeki argümanların isteğe bağlı olarak numaralandırılmasıdır. İkinci parantez ise fonksiyonumuz çağrıldığında yapılacak işlemleri içerir. Fonksiyonun bu tanımı mümkün olan tek tanım değildir, ancak bunu kullanacağız (diğerleri resmi belgelerde bulunabilir).


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


Özel workDaysBetween işlevimiz, argüman olarak iletilen bugün ile başlangıç tarihleri arasındaki çalışma günlerini hesaplayacaktır. Fonksiyonun mantığı çok basittir: İzin günlerini sayarız ve bunları tarihler arasındaki toplam gün sayısından çıkarırız.


İzin günlerinin sayısını hesaplamak için bugün ile bugün arasında kaç hafta geçtiğini bulmamız gerekir. Bunu yapmak için her haftanın sayıları arasındaki farkı hesaplıyoruz. Bu sayıyı bize yılın başından itibaren hafta sayısını sağlayan Weeknum işlevinden alacağız. Bu farkı ikiyle çarparak geçen gün sayısını buluruz.


Daha sonra HOURS_BETWEEN işlevi tarihlerimiz arasındaki saat sayısını sayar. Sonucu 24'e bölerek gün sayısını buluruz ve bu sayıdan izinli günleri çıkararak tarihler arasındaki iş günlerini buluruz.


Yeni fonksiyonumuzu kullanarak bir grup yardımcı değişken tanımlayalım. Tanımlardaki bazı tarihlerin, örneğin başında bahsettiğimiz global değişkenler olduğunu unutmayın.


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


Kodu okumaya uygun hale getirmek için koşulların sonuçlarını saklayan değişkenleri tanımlayalım.


 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 değişkeni için, gelecekteki satırı basitleştirmeme yardımcı olan isteğe bağlı bir koşul ve not(çözünürlük) ekledim, çünkü görev zaten kapalıysa, o zaman onun son oluşturulmasıyla ilgili bilgilerle ilgilenmiyorum.


Nihai sonuç, satırları birleştiren concat işlevi aracılığıyla oluşturulur.


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


Emojinin sadece koşuldaki değişken 1'e eşit olduğunda satırda olacağı ortaya çıktı. Böylece satırımız görevdeki bağımsız değişiklikleri eş zamanlı olarak görüntüleyebiliyor.


Sütunun değişikliklerle birlikte son görünümü (sol taraf)


İzin günleri olmadan çalışma günlerini sayma konusuna değindik. Bununla ilgili son örneğimizde inceleyeceğimiz ve aynı zamanda dizileri tanıyacağımız bir sorun daha var.


İzin günleri hariç çalışma saatlerinin hesaplanması

Son gösterim örneği


Sorun

Bazen bir görevin izin günleri hariç ne kadar süredir çalıştığını bilmek isteriz. Bu, örneğin yayımlanan sürümü analiz etmek için gereklidir. Neden izin günlerine ihtiyacımız olduğunu anlamak için. Ancak biri pazartesiden perşembeye, diğeri ise cumadan pazartesiye koşuyordu. Böyle bir durumda takvim günlerinin farklılığı bize bunun tersini söylese de görevlerin eşdeğer olduğunu söyleyemeyiz.


Ne yazık ki, "kutudan çıktığı haliyle" Yapı izin günlerini nasıl göz ardı edeceğini bilmiyor ve "Durumdaki zaman..." seçeneğinin bulunduğu alan, Jira ayarlarından bağımsız olarak bir sonuç üretiyor - Cumartesi ve Pazar izin günleri olarak belirtilmiş olsa bile.


Sonuç olarak amacımız, izin günlerini göz ardı ederek tam iş günü sayısını hesaplamak ve durum geçişlerinin bu süre üzerindeki etkisini hesaba katmaktır.


Peki statülerin bununla ne ilgisi var? Cevap vereyim. Diyelim ki 10 Mart ile 20 Mart arasında görevin üç gün boyunca iş başında olduğunu hesapladık. Ancak bu 3 günün bir günü duraklamada, bir buçuk günü de incelemede kaldı. Görevin yalnızca yarım gün boyunca iş başında olduğu ortaya çıktı.


Önceki örnekteki çözüm, durumlar arasında geçiş yapma sorunu nedeniyle bize uymuyor çünkü özel workDaysBetween işlevi yalnızca seçilen iki tarih arasındaki süreyi hesaba katıyor.


Önerilen çözüm

Bu sorun farklı şekillerde çözülebilir. Örnekteki yöntem performans açısından en pahalı olanıdır ancak izin günlerini ve durumları sayma açısından en doğru olanıdır. Bu uygulamanın yalnızca 7.4'ten (Aralık 2021) eski Yapı sürümünde çalıştığını unutmayın.


Yani formülün arkasındaki fikir şu şekildedir:


  1. Görevin başlangıcından bitişine kadar kaç gün geçtiğini bulmamız gerekiyor
  2. Bundan bir dizi, yani görevle ilgili çalışmalarımızın başlangıcı ile bitişi arasındaki günlerin bir listesini yaparız.
  3. Listede yalnızca izinli günleri tut


Tüm tarihlerden yalnızca hafta sonlarını filtreleme (farklı durumlara sahip olabilirler)


  1. Bu izin günlerinin dışında, yalnızca görevin "Devam Ediyor" durumunda olduğu günleri tutuyoruz (7.4 sürümünün "Geçmişsel Değer" özelliği burada bize yardımcı olacaktır)


"Devam ediyor" durumu kalacak şekilde gereksiz durumları kaldırma


  1. Artık listede yalnızca "Devam Ediyor" dönemine denk gelen izin günlerimiz var
  2. Ayrı olarak, “Devam Ediyor” durumunun toplam süresini buluyoruz (yerleşik Yapı seçeneği “Durumdaki süre…” aracılığıyla);
  3. Daha önce elde edilen izin günlerinin sayısını bu süreden çıkarın


Böylece, izin günlerini ve ekstra durumlar arasındaki geçişleri göz ardı ederek görev üzerinde tam çalışma zamanını alacağız.


Kullanılan yapı özellikleri

  1. Değişken eşleme
  2. Expr dil yöntemleri
  3. Yerel değişkenler
  4. Koşullar
  5. Dahili bir yöntem (kendi fonksiyonumuz)
  6. Diziler
  7. Görev geçmişine erişim
  8. Biçimlendirmeli metin


Bir kod örneği

 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}"""


Çözümün analizi


Algoritmamızı koda aktarmadan önce Yapı hesaplamalarını kolaylaştıralım.


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


Eğer satır bir görev değilse veya durumu “Açık” ise o satırları atlayacağız. Yalnızca çalışmaya başlatılan görevlerle ilgileniyoruz.


Tarihler arasındaki gün sayısını hesaplamak için öncelikle şu tarihleri belirlememiz gerekir: FinishDate ve startDate.


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


İşin mantıksal sonunu ifade eden durumları belirlemek


Görev tamamlanma tarihinin (finishDate) şöyle olduğunu varsayacağız:

  • Görevin "QA" durumuna aktarıldığı tarih
  • Ya “Kapalı”ya geçiş tarihi
  • Veya görev hala “Devam Ediyor” durumundaysa bugünün tarihi (ne kadar zaman geçtiğini anlamak için)


İş başlangıç tarihi startDate, “Devam Ediyor” durumuna geçiş tarihine göre belirlenir. Görevin çalışma aşamasına geçmeden kapatıldığı durumlar vardır. Bu gibi durumlarda kapanış tarihini başlangıç tarihi olarak kabul ettiğimizden sonuç 0 gün olur.


Tahmin edebileceğiniz gibi toQA, toDone ve toProgress ilk ve önceki örneklerde olduğu gibi uygun durumlarla eşleştirilmesi gereken değişkenlerdir.


Ayrıca yeni DEFAULT(toProgress, toDone) fonksiyonunu da görüyoruz. toProgress'in bir değeri olup olmadığını kontrol eder, yoksa toDone değişkeninin değerini kullanır.


Daha sonra statusWeekendsCount özel fonksiyonunun tanımı geliyor, ancak tarih listeleriyle yakından ilişkili olduğundan ona daha sonra döneceğiz. Doğrudan bu listenin tanımına gitmek daha iyidir, böylece daha sonra işlevimizi ona nasıl uygulayacağımızı anlayabiliriz.


Aşağıdaki formda bir tarih listesi almak istiyoruz: [startDate (11.03 diyelim), 12.03, 13.03, 14.03 … FinishDate]. Yapıda bizim için tüm işi yapacak basit bir fonksiyon yoktur. O halde bir numaraya başvuralım:


  1. 0'dan çalışılan gün sayısına kadar olan bir sayı dizisinden basit bir liste oluşturacağız, yani [0, 1, 2, 3 … n işteki gün]
  2. Her sayıya (yani güne) görevin başlangıç tarihini ekleyin. Sonuç olarak, gerekli türden bir liste (dizi) elde ederiz: [başlangıç + 0 gün, başlangıç + 1 gün, başlangıç + 2 gün … başlangıç + n çalışma günü].


Başlangıç tarihinden mantıksal bitişe kadar başlangıç tarih dizisi oluşturma


Şimdi bunu kodda nasıl uygulayabileceğimize bakalım. Dizilerle çalışacağız.


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


Bir görev üzerindeki çalışmanın kaç gün süreceğini sayıyoruz. Önceki örnekte olduğu gibi, 24'e bölme ve hour_between(startDate,finishDate) işlevi aracılığıyla. Sonuç, generalDays değişkenine yazılır.


SequenceArray değişkeni biçiminde sayı dizisinin bir dizisini oluşturuyoruz. Bu dizi, SEQUENCE(0,overallDays) işlevi aracılığıyla oluşturulur; bu, 0'dan genelGünlere kadar bir diziyle istenen boyutta bir dizi oluşturur.


Sonra sihir geliyor. Dizi işlevlerinden biri haritadır. Belirtilen işlemi dizinin her elemanına uygular.


Görevimiz her sayıya (yani günün sayısına) başlangıç tarihini eklemektir. DATE_ADD işlevi bunu yapabilir, belirtilen tarihe belirli sayıda gün, ay veya yıl ekler.


Bunu bilerek dizenin şifresini çözelim:


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


SequenceArray'deki her öğeye, .map() işlevi DATE_ADD(startDate, $, "day") uygular.


DATE_ADD için bağımsız değişkenlerde neler aktarıldığını görelim. İlk şey, istenilen sayının ekleneceği tarih olan startDate'dir. Bu sayı ikinci argüman tarafından belirtilir, ancak $ görüyoruz.


$ sembolü bir dizi öğesini belirtir. Yapı, DATE_ADD fonksiyonunun bir diziye uygulandığını anlar ve bu nedenle $ yerine istenen dizi öğesi olacaktır (yani 0, 1, 2…).


Son argüman olan "gün", bir gün eklediğimizin göstergesidir, çünkü işlev, belirttiğimiz şeye bağlı olarak bir gün, ay ve yıl ekleyebilmektedir.


Böylece, dateArray değişkeni işin başlangıcından tamamlanmasına kadar bir tarih dizisini saklar.


Kaçırdığımız özel işleve geri dönelim. Fazladan günleri filtreleyecek ve geri kalanı hesaplayacaktır. Bu algoritmayı örneğin en başında, kodu analiz etmeden önce, yani izin günlerini ve durumları filtrelemeyle ilgili 3. ve 4. paragraflarda açıkladık.


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


Özel işleve iki argüman ileteceğiz: bir tarih dizisi, buna tarih diyelim ve gerekli durum - durum. Aktarılan tarihler dizisine .filter() işlevini uygularız; bu, dizide yalnızca filtre koşulundan geçen kayıtları tutar. Bizim durumumuzda bunlardan iki tane var ve bunlar ve ile birleşiyor. Filtreden sonra karşımıza çıkan .size() fonksiyonu, üzerindeki tüm işlemler bittikten sonra dizinin boyutunu döndürüyor.


İfadeyi basitleştirirsek şuna benzer bir şey elde ederiz: array.filter(koşul1 ve koşul2).size(). Böylece sonuç olarak bize uygun olan izin gün sayısını, yani şartları aşan izin günlerini elde ettik.


Her iki duruma da daha yakından bakalım:


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


x -> ifadesi, filtre sözdiziminin yalnızca bir parçasıdır ve x dizisinin öğesini çağıracağımızı belirtir. Bu nedenle, her koşulda x görünür ($ ile olduğu gibi). Aktarılan tarihler dizisindeki her tarihin x olduğu ortaya çıktı.


İlk koşul, haftanın günü(x) > 5, x tarihinin haftanın gününün (yani her öğenin) 5'ten büyük olmasını gerektirir; bu ya Cumartesi (6) ya da Pazar (7).


İkinci koşul tarihsel_değeri kullanır.


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


Bu, 7.4 sürümünün Yapısının bir özelliğidir.


İşlev, görevin geçmişine erişir ve belirtilen alanda belirli bir tarihi arar. Bu durumda “durum” alanında x tarihini arıyoruz. Bu değişken, işlev sözdiziminin yalnızca bir parçasıdır, otomatik olarak eşlenir ve satırdaki geçerli görevi temsil eder.


Böylece koşulda, dizideki her x tarihi için aktarılan durum argümanı ile tarihsel_değer fonksiyonunun döndürdüğü “status” alanını karşılaştırırız. Eşleşirlerse giriş listede kalır.


Son dokunuş, istenen durumdaki gün sayısını saymak için fonksiyonumuzun kullanılmasıdır:


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


İlk olarak, dateArray'imizde “Devam Ediyor” statüsünde kaç gün izin alındığını bulalım. Yani, tarih listemizi ve istenen durumu, statusWeekendsCount özel işlevine iletiriz. İşlev, görevin durumunun "Devam Ediyor" durumundan farklı olduğu tüm hafta içi günleri ve tüm izinli günleri ortadan kaldırır ve listede kalan gün sayısını döndürür.


Daha sonra “Time in status…” seçeneği ile haritaladığımız timeInProgress değişkeninden bu tutarı çıkarıyoruz.


86400000 sayısı milisaniyeleri günlere çevirecek bölendir. Sonucu onda birine, örneğin “4.1”e yuvarlamak için .round(1) işlevi gereklidir, aksi takdirde şu tür bir giriş elde edebilirsiniz: “4.0999999 …”.


Görevin uzunluğunu belirtmek için renk değişkenini tanıtıyoruz. Görevde geçirilen gün sayısına bağlı olarak bunu değiştireceğiz.


  • Gri — 0 gün
  • Yeşil — 0'dan fazla ancak 2,5 günden az
  • Kırmızı – 2,5 ila 4 gün arası
  • Kırmızı – 4 günden fazla


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


Ve hesaplanan günlerin sonucunu içeren son satır:


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


Sonucumuz aşağıdaki resimdeki gibi görünecektir.


Çalışma Süresi alanının son görünümü


Bu arada, aynı formülde herhangi bir durumun zamanını görüntüleyebilirsiniz. Örneğin, "Duraklat" durumunu özel fonksiyonumuza aktarırsak ve timeInProgress değişkenini "... içindeki süre — Duraklat" aracılığıyla eşlersek, duraklatmadaki tam süreyi hesaplayacağız.


Durumları birleştirip “wip: 3.2d | rev: 12d”, yani çalışma süresini ve inceleme süresini hesaplar. Yalnızca hayal gücünüz ve iş akışınızla sınırlısınız.


Çözüm

Jira görevlerini analiz etmek için benzer bir şey yapmanıza veya tamamen yeni ve ilginç bir şey yazmanıza yardımcı olacak bu formül dilinin çok sayıda özelliğini sunduk.


Umarım makale formülleri anlamanıza yardımcı olmuştur veya en azından bu konuyla ilgilenmenizi sağlamıştır. “En iyi kod ve algoritmaya” sahip olduğumu iddia etmiyorum, dolayısıyla örnekleri nasıl geliştirebileceğinize dair fikirleriniz varsa paylaşırsanız sevinirim!


Elbette, hiç kimsenin size formülleri ALM Works geliştiricilerinden daha iyi anlatamayacağını anlamalısınız. Bu nedenle belgelerine ve web seminerlerine bağlantılar ekliyorum. Özel alanlarla çalışmaya başlarsanız, diğer hangi özellikleri kullanabileceğinizi görmek için bunları sık sık kontrol edin.