From dccb499ac341bd236887ccd11a1ca4045bc35dd7 Mon Sep 17 00:00:00 2001 From: Pranav Gaikwad Date: Thu, 16 Mar 2023 15:14:22 -0400 Subject: [PATCH 1/3] add dynamic reports enhancement Signed-off-by: Pranav Gaikwad --- enhancements/dynamic-reports/README.md | 165 ++++++++++++++++++++ enhancements/dynamic-reports/components.png | Bin 0 -> 7426 bytes 2 files changed, 165 insertions(+) create mode 100644 enhancements/dynamic-reports/README.md create mode 100644 enhancements/dynamic-reports/components.png diff --git a/enhancements/dynamic-reports/README.md b/enhancements/dynamic-reports/README.md new file mode 100644 index 00000000..8ff1852e --- /dev/null +++ b/enhancements/dynamic-reports/README.md @@ -0,0 +1,165 @@ +--- +title: Dynamic Reporting +authors: + - "@pranavgaikwad" +reviewers: + - "@rromannissen" + - "@jwmatthews" + - "@jortel" +approvers: + - "@rromannissen" + - "@jwmatthews" + - "@jortel" +creation-date: 2023-03-15 +last-updated: 2023-03-16 +status: implementable +--- + +# Dynamic Reports + +The results of source code and binary analysis are vital to assessment of applications. They enable users to define and plan appropriate migration strategies in the later stages of the Konveyor methodology. So far, Konveyor relies on Windup output to present the results of these analyses. It is largely static and isn't stored in Konveyor. It is limiting in that Konveyor cannot aggregate the analysis results for multiple applications in the inventory. + +In this enhancement, we present Dynamic Reports. Dynamic Reports use the analysis data created by the new LSP analyzers. They can be generated on-demand for one or more applications from the most recent analysis data available in Konveyor. They enable users to see analysis information of multiple applications in one place with better control over what's displayed. + +## Motivation + +With the upcoming integration of new LSP analyzers in Konveyor, the data generated by analyzers becomes a first class entity in Konveyor. We talked about this in our previous enhancement on [Reporting Format](./TODO: Link here). It opens up lots of possibilities for Konveyor in terms of what it can do with the data. We want to leverage that and improve reporting capabilities of Konveyor. Dynamic reports are simply reports that give users much more control on what information is displayed via filters, visualizations, etc. They bring important information across all applications in the inventory in one place and make it easier for users to query that information. + +### Goals + +We only intend to define requirements and scope for dynamic reports. + +### Non-Goals + +We do not intend to discuss technical details in this enhancement. More enhancements will follow for technical details on implementation. + +## Proposal + +The three main components of the dynamic reports we are proposing are Issues, Dependencies and Facts. + +Issues and Dependencies are the primary components that will be aggregated over multiple applications, whereas Facts are specific information showed only in the context of a specific application. Note that the analyzers create data pertaining to all three components for one application at a time. + +![components.png](./components.png) + +### Issues + +An issue is analogous to a _Violation_ created by the analyzer. They are created when analyzer finds a match for a Rule. + +Issues have following properties: + +* Description: A text description in markdown format +* Rule ID: Rule for which the issue was created +* Category: Helps define severity of issue +* Effort: A numeric value denoting efforts needed to fix the issue +* Hyperlinks: External links that provide additional information pertaining to the issue +* Incidents: Occurrences of the issue across the source code. Each incident will have a file URI and a message that helps show information about that particular incident. + +### Dependencies + +Analyzers output dependencies for an application with each dependency having following properties: + +* Name: Name of the dependency. +* Version: Version of the dependency. +* SHA: Checksum of the dependency. +* Indirect: Whether the dependency is indirect. +* Type: Type of the dependency. + +### Facts + +Facts are additional application specific data generated by the analyzers. Depending upon application technology, different analyzers (providers) + will generate different type of data for an application. The application facts will be generated from this information. Examples of application facts for a Java application are: + - Enterprise Java Beans reports + - Java Persistent API usage reports + - Spring Beans reports + - Hibernate session usage + +Facts are data that don't necessarily fit into the notion of "issues" or "dependencies". Since the data types for facts are arbitrary, we do not envision aggregating this data at the portfolio level. Facts will only be presented in the context of an application. Filtering / querying application facts will not be possible due to the nature of the data. + +### User Stories + +We define two scopes for the reports: + +* Portfolio scope: This is the part of report which is in the context of all or a selected subset of applications in the inventory. + +* Application scope: This is the part of report which is in the context of one specific application. + +#### Portfolio scope + +##### Dependencies + +* As a user, I want to be able to see a list dependencies across all applications in the inventory. + +* As a user, I want to be able to filter dependencies by applications and whether the dependency is a direct or an indirect dependency. + +* As a user, I want to be able to see a list of dependencies shared by two or more applications in the inventory. + +##### Issues + +* As a user, I want to be able to see a list of all issues generated by the analyzer for all applications in the inventory. + +* As a user, I want to be able to filter issues by applications, category, effort and source/target technologies. + +* As a user, I want to be able to use more than one filters at a time to further narrow down my search of issues. + +##### Statistics + +* As a user, I want to see total number of "mandatory" issues aggregated across all my applications from most recent analyses available. + +* As a user, I want to be able to see all categories of issues with their associated story points aggregated across all my applications from most recent analyses available. + +* As a user, I want to be able to filter statistics generated from most recent analyses by applications. + +* As a user, I want to be able to see trend of "mandatory" story points generated from the history of all analyses. + +* As a user, I want to be able to see trend of number of issues in each category from the history of all analyses. + +#### Application scope + +##### Dependencies + +* As a user, I want to be able to see a list of dependencies for a specific application. + +* As a user, I want to be able to see a tree of dependencies so that I can distinguish between a direct and an indirect dependency. + +* As a user, I want to be able to filter Java dependencies by package groups. + +##### Issues + +* As a user, I want to be able to see a list of issues for a specific application. + +* As a user, I want to be able to filter the issues by their category and efforts. + +* As a user, I want to be able to see breakdown of number of issues per category with associated story points for each category. + +* As a user, I want to be able to see breakdown of "mandatory" issues by effort with associated story points for each level of effort. + +* As a user, I want to be able to see number of issues generated per Java package. + +###### Facts + +* As a user, I want to be able to see all tags generated for the application including categories of tags created. + +* As a user, I want to be able to filter tags by categories (tag types). + +* As a user, I want to be able to see Enterprise Java Beans in an application. + +* As a user, I want to be able to see Java Persistence API usage with details including persistent units, entities and queries. + +* As a user, I want to be able to see a list of Spring Beans in an application with details including Bean Name and Class. + +* As a user, I want to be able to see Hibernate session factories and entities in an application. + + +### Implementation Details/Notes/Constraints + +#### Multiple Filters + +One or more filters can be combined together to form complex searches. When using multiple filters, logical AND will be implied. In the future, we can probably expand the scope to have logical ORs in the filters. But right now, it's out of scope. We do not intend to support advanced operations like ANY, IN, etc. + +#### Filter dependencies by Java package groups + +From analyzers perspective, Name field of a dependency would have fully qualified name for the dependency. It makes the most sense to have a generic "Name" field to accomodate all different kinds of dependencies out there for different technologies. As a result, implementing a filter based on Java package group names implies a full text search within names of dependencies. + +#### Historical data + +Contents of the dynamic report are generated from most recent analysis data except for "trends". For trends, we want to store the computed statistics of the analyses and not the entire output. We want to limit the data points we store. But we are not defining a limit on the period of time for which the data stays. diff --git a/enhancements/dynamic-reports/components.png b/enhancements/dynamic-reports/components.png new file mode 100644 index 0000000000000000000000000000000000000000..b0315c1ddff9aa115186ac1a1210c52105bbd737 GIT binary patch literal 7426 zcmc(EcT`hNv~Mg(Q$Zx4bfhT(K@gBGO`3EFp#)6mO?q!4A^`*hq&ESn31H|gqCh~3 z^Z-&nKx!cL8p?~`UF)s){ZH7%-k=kTHy4oyv&?}$PWp! z%36-DJ~oc-`GsY6E?#;N%h-gJ@W@y*m;=PZCMN!qUvPMRBc>Gjwc=|n%oe3as zrm8XkLB^^^Vkq6zOgsUAdzpXVE9&0ipGZP-FLf;y@|A0}cPJl!pB|wH0GQ>~l@$#A zCO5NhwIa)sBaM`w?-XVSx=LqD78m=@PNs)k4oCLo#k2v#;dD|Q|AKc z-UAlGlVeddMhPXl; zZph>rPY+vmc!7gqh!=ylTInF|>cT2Z7Oft8cKG6xnIXw%oNX*5a!vOJ(eqAk+RF8 z{Cp{p_i_YO*enD3bX#b@2P!INTDsFkQ}E6^K7bSI(T1r^`(_R%=td}XnU`MY4u{-1 z<^WgXbU`bLhCP?VBZ*A0cT4fpq1@>PAlYZ<&fwb`lnHhOpvu6<=uY**8Y7q=O80!| zik$9^SE_P|!k2{eo+^!7`$5HyWwonEHFd^h=><~iLdH*-NDf~x|jpI!&s|*B3 zV9)1T!)0kfSJ|=o6^WIF&i2&mu^y<<7B^m*Z7myG%@0D&J?p1cM+tHdBiw@#z%Uy4 z+SD~ImptQkbwfHbf9n>JAEhynJj~vfcwW9|EkrxumTK3L+Wj}IClmgyviE*Q$CzT02ctF0-n1~iJzWjsL6_}7efU$naga>qaaOp> z{5J@<5q_!@K529+FjjbFQ;|^s!BgwlyptwP>aitaDL{?&7F?UdN-DK#4TzG^P; zn|X1=;a2I=$ZSW`#lsFZ($~R7@UsX1E-~b_RYXxJgGOKQ40}gH^biIm`lI|&xs+Tf zKQiwY>uP3fxp~=>r~b?A@fM2R;Q(LPEqNIJ@UyPo4ZY`i`8V_5D5~67z7i2Fg1AZr zw4o)V=kMX5dT97bfu2C`sNLEvtZeLaY01F}zMeu|I~r{4@ug({qPm4-h=Cec7PfW% zCVZAy@psCwisdE)k17to9g)LTUX|+Z6{kE6xPLNB9s3+bApk71kt=SPJ*f~OsTL|O zSq$Q6TW@}Up-=C$b>6dgJzVrV}j)mu@vdfOUrxy%#mnlX-d>#DyCyFGe z`WTMFAn`#K#Zoz-@fDxJ_M!B&9R$Rm6S5sC-_P#qLJp3>xmy_Fc1=GzV<1)flWt$w zd~2p^Z!!#_#><5un;K1~0wzv5T<|N;`_D7#1`sJ?%Lo>|MVSFtd z*yro^B#VC(2X`k}4C*&A6Re;hhNGB_u#sOzPFVi*EtwLDee;0_49K%`pysIR%Dz+I zdzB^5u^5r0g$ZyyXDBURC0$()C3q4J5$d_wF?s3gCKR4(eFMIEAfa*4gQJ3Eb0Nsk z7Af};wc~SdAUd*Ll(TRXJtLKSZMEqpn(6;x-lzDhH@)z7YjsqNomcpf)NS9a)*Hsg~8kqKDnLhFNOn>OA z)w$UI_!Q}R9la1!*zVIgx*R*z&yb%LB}SMeWHGH$mev26Q2thO(}x_6WpvUVKM`N3 zyGArby@+TuOu1kkO+uooq*Q6~WWfUCR_oGpF{zWRw?k$}4F#U`=b_XEG%S2|%(X}= z%vdRG!1hojRj)#lnb(BR#b5|MK3Yec{Jb4E7S$ou6|jAz{j(L}W7I^P?nE>3jXu-) zN*^%npK28=7MSZSRmgVXv~mZ}jsGzx&AHBafOp*-7@4t?dhUqxUUyTMEr0NHR5wvS zIOD)vMy@V^4Xs_pb_PYugr1h4sW%b*&>D+d2Olw2jg(1yfxdTEoAgIbX+9~(F~-$Z zeagDM#2n+Da_~cRkdc|msk?xkv5VlX_bC^SL!Zi9 zZN097wJgA{)ATtuvd6j6OUJ#fVgr`Ib-Y_Mi|XtnyNJ-qQWdVPnavZQvm}~OCmk*Z zZAD zy3j7XY^n?G*BJ=0odu(4e3xFc`>)*Jf~EUgp?ywd2s>uWLl;SdW2|mqk&RRt z2APtJ4hZ{x8&8-wi7o!PvF z8U|km1=RJGAMzaFPVZD+AIoJ7R>Pg`%nBZ6v>^zN-us8-iw+rLh_oHUGJYgy;(Hh0 zE2D%ue*>WfQPEPvRj$AlP!FFAAb@0~e!4<|qBMJg;@r7?KCdnD$ zVUZAe1sdcqNt7z>S+!sWZ16OA>6FWSjY2>@2wBYXF)a_2- z7tc7x0?-<>5~$tQy8$juzIS7Yf`{)%Vk2nrGBIzxvUbVQ{iKC(rXYauwzuT~XQ0so zebm^VUPP;o+g+rfaoinL!|(g>V6D)pi7l}mIZiMk^s`eP4a@yn557`hrnmx1C{NIN zA(nHCd(0*`I|OgaLW{S78zU&tKMA@4!IR7mjG-IOw-eRj} zXU#=*?J)0|wZn|%s8V%W>mrPg!6j9|dsX+|E<(HpmuGC%W9u|b|1yB6_5_WEPZUSHn}&z`Ne1jL}gJeTi)1-YnxtA-0hn{p8)m zF&m!SI7gzzMI$VZX3KvV&1MecRp2LlrTdyd-f|f<<|`*;VLc3jWsss=_|tYq?)Q)Y)6Q`wWG*SovQ>#%8Rx0Etb53C;E@G6@G}d~ z4knwv6grX)qDL}cW3ZmXD6?amW_uD&90*pDn+Au(Dml^NLEz4QN`d^w;}p#8*i+XU z#9)_c$##f^RU@jhJ+qNhAWwKawh40Vy13CjI{5ohI|X>wm02&S=+PNg;$3gB02A%cQtey! zQ|D`icmMSJ2d)JTQG43$A4|Ta1I9#UY#ZCZat<;We0uX^H#%!q$KCCfrmc@F)m}FT z5USNYY+O`&R-f2Jj{ycO4#?8P96--Q8U@Y-z!vXzuJ$;r9{CyJwzMwAq4?D5T2gJqSLV>1 z5H*zRUT<>5?_1tthjG?RLN?9YrkaeL^CC_A@)|g=Q@j2@vl`4H!wy^A`Tdv2XU7wk zGshZV57>n<>9p|ji)%?2hK(+1Fr%FDOYp;UXiN2#dnR!s)j`^3fx%B)GybuY`v%LZ z9yi@}%3Adm(gVj?7EUcr*}RgpB){?(?~FZ-&h}{1agO|9j+(OOLmU|XOJX^@F^dt9 zK9TTdF9wHS3O3)%HaHnxU&2%GBe2w9QUXOA1GVK~5P~eZCP6^s;VaiWG&n?^NJK|E zR-}DMGVN>WS8xUS0LeMKWYDv+gFz;*i9>!f0oz#<55UNKl`g$5JiRUtP-ZkacQYC4 zH%%&mCg`4-7k9wr|DtLG{xN*i_wj|NBc*Q%EaV%T44-(^(#la(BImEqVwFAtTSfR$ zEzTLtU@$7*{}q*XOp6_@(;Gf-XjN2` z$g6~+*bro>EFYCeKcl24CE71Al&Y4 zjjc%l$qI$Bd+y2)&-wm}WEw)!(Ye?E7$x`GYe{-xqiahXukgH8<%PV~j2!Hp{CbZyCjE>Xi;D2iv&E;m_c|r*dj$4A{5bSXf>qlN31OAW7%HT94njNYlA?TeAFX1Hn7C zRKGw}TIA`FV&B1L$m>OS>nOp7ReqQLa8lh<%*h6{ubWr(klNX%LVwxWD}KNI#@2Vu zc6xl;+Jl08;8)%&@5d%K%N$Lb_k$X63o){J?6Aivx~5N!CPXnf4c~BZHqqYZUE$1_ z3Ri%b%u(dCY)x>wB;qsxJvQ+Ac0tc#|Kr1W;kzIjjR-+GC;8Ui;l~HC)P>pBw4>$H zv5&Y$fwW8b<<&nf;vdqqQuclg`yLQ&W+qm!bX@z9ZL^2mBMqX#yiAhOHij4&FDD4? zfpfn6Sc9&oQW-n{Qqgde?kqpVufC2(;-ic|my|)0!H8@~IE0XHAtSpMlMFGzI=#T- z9q`>JZkV+Y`_3O>-M^^jaFx(z%~)?7s*eh%Lw7QNBd=6qF8lKyA-bwAh|i;|cxZ2| zYt3^-JMGj}dLPZyMD=N3M?D*4jTCu zo;ia499ZKy?>e8TGuwmJK`H4uyUOR7ByVzo^Sp9Q3R1e`)S29WOM;pZ&oU(>mR-L|^Q+ z8~xfFvE_}Qtk`N6Ny_(d$=&!+rW8AIPh-sMqH4eKOc8ZI2zyF#bhk@3ROkjAqj_O* zvm+q&408{0@c1O~2`wJFdj#hgYyPu^eU9?&o{I^CY$dibUPI6F`~_^Pbjkc%k|86; z$7X_c#8K|H;wNpX{@kDoxNPMMepiK}~ddi$fw?5Q@=hVCx)m#ZCD^^S!QWbo~|OHZ%c z-|r`AY;RTL5+3I8flMcAxH#_cIhGRcqbzB!Od;QKyG$Cl-~G_~AVyZil{aBd9o zX4AyQ{Z}BqmQAkR{@1U7eDwHtoIDgq#B5sq{H$$(Ea5NLCFf0^!PF={+N#~!KGOYp zXE#q$`AIp@MyaF`vs{=WV=_gRRS_94yM z)?Xf-x~VcSOgF38#!ci(D0ZTB<%H>vC49Km6<@H2=9*Jfn~Ur33cSk{x3%Ix300d5 zRJG*oNssw)dKJ1+B$%UIx?&R7Fql#H3?>d}GR zh|TM=hPrJX)fJdsNETj1LeJdncxuRhB7GtC?yY0qn7?{ciZ$=L_BIDpS6=ysoIR5w z|6UtGiV_p7Vdu7NT=8g){mTpX7@)=Bht1r}>8vuuZ11 zpQNYr1`IQ?&s^e!MPt7T0<4~X|gV@(-F7ZU2nel#6=+o57Id1>yGoFq_i1pa>%h7SDerd-Vgy`W~ zBVXhJ)Hwci^#*^?qg68Ijtm|q#eAPLFJnIaQ#Yn&v%O5_1K3I!R|ggBp=s;7N16fc z{GwtJb*`Reb?u%s%CoYCZ12eB za7dfoq)PG#qZ0MhLA-0n&U-ke6n*OY3vw+DOKQs9uF!N4Dc%37QZma|HBT*2QXr=J zR80zou`JG97gg%=it_+EcFkfWXq@~cl6bn~Xpx8TmB~Np10lS`rt~NtrR2wWU6z`g z#+uz$D?*$p*j=*e$cn@-iyqSw(+$IdT|Cp7uW~KrP+vk@pcfG9%?YzcZpU`&&85nk zw)dV-zjYg#PlppSqK)FF-T?Ot@wlWIxo>%pTmB1Wbgkco zD1Fv&RO9f3XUeLDfje(4Dl1fkilQb>@_SDjWeDbY)wIFshXysiyY)PE$?t?`LWw(4 zSX^F($<18xJIH$l%q2fJ1pPNi6NxF(jns;|3f~19c^wLUs$LMck_dk(K;S9kP1g4t zAq!q3KT5)PDOFGf$3uM$fsC@Ox7nq(k{-AX-2BwSxY{yD`T9XhrCgS-4F`=Dl;J}) ztOdD0KH*6^%!TM?*Js%u>slFA?1?MtsGF^=#m$n(T8V|<W@95#;!g%3u^jg>E0x)m8E)$JMNYgYROqU5c+y`x;!KbZg%qvAl8a9-S{FoEUpw@y4?TgDertFy~@3rohZ56SMKA?n4q+a zi#cp|g+9e)l-It_e5sXDLlG-0D-km@y3d7Uecmkhl2(!_yYj;!ga=OjUd8)AFeg+@MEh0C&>dfx6TPW1l0TbgW9iVKC;U+OpCY~a7@RbnH|8yl589E%t*Xu& zkM<7-5Qyoj`d{f*R-_ZwtC2$3*CrwhedwLyVWH`~ExpMA11F#5i3u+JYPzX{iFETJ**Miy76YY?zv{OcQ>n8GGZubcaO(O(b8EUv5Rk#i|(P zkysut6^NHL%*#f~%EN|K07QgEL Date: Tue, 21 Mar 2023 10:47:11 -0400 Subject: [PATCH 2/3] add details on some of the stories Signed-off-by: Pranav Gaikwad --- enhancements/dynamic-reports/README.md | 83 ++++++++++++++++++-------- 1 file changed, 58 insertions(+), 25 deletions(-) diff --git a/enhancements/dynamic-reports/README.md b/enhancements/dynamic-reports/README.md index 8ff1852e..d33b31d1 100644 --- a/enhancements/dynamic-reports/README.md +++ b/enhancements/dynamic-reports/README.md @@ -11,7 +11,7 @@ approvers: - "@jwmatthews" - "@jortel" creation-date: 2023-03-15 -last-updated: 2023-03-16 +last-updated: 2023-03-21 status: implementable --- @@ -19,11 +19,11 @@ status: implementable The results of source code and binary analysis are vital to assessment of applications. They enable users to define and plan appropriate migration strategies in the later stages of the Konveyor methodology. So far, Konveyor relies on Windup output to present the results of these analyses. It is largely static and isn't stored in Konveyor. It is limiting in that Konveyor cannot aggregate the analysis results for multiple applications in the inventory. -In this enhancement, we present Dynamic Reports. Dynamic Reports use the analysis data created by the new LSP analyzers. They can be generated on-demand for one or more applications from the most recent analysis data available in Konveyor. They enable users to see analysis information of multiple applications in one place with better control over what's displayed. +In this enhancement, we present Dynamic Reports. Dynamic Reports use the analysis data created by the new LSP analyzers. They can be generated on-demand for one or more applications from the most recent analysis data available in Konveyor. They enable users to see analysis information of multiple applications in one place to get a high level of migration issues across their portfolio. At the same time, they allow the users to drill down into specifics of each issue. ## Motivation -With the upcoming integration of new LSP analyzers in Konveyor, the data generated by analyzers becomes a first class entity in Konveyor. We talked about this in our previous enhancement on [Reporting Format](./TODO: Link here). It opens up lots of possibilities for Konveyor in terms of what it can do with the data. We want to leverage that and improve reporting capabilities of Konveyor. Dynamic reports are simply reports that give users much more control on what information is displayed via filters, visualizations, etc. They bring important information across all applications in the inventory in one place and make it easier for users to query that information. +With the upcoming integration of new LSP analyzers in Konveyor, the data generated by analyzers becomes a first class entity in Konveyor. We talked about this in our previous enhancement on [Reporting Format](./TODO: Link here). It opens up lots of possibilities for Konveyor in terms of what it can do with the data. We want to leverage that and improve reporting capabilities of Konveyor. Dynamic reports are simply reports that give users much more control on what information is displayed via filters, visualizations, etc. They bring important information across all applications in the inventory in one place and make it easier for users to query that information. ### Goals @@ -87,32 +87,41 @@ We define two scopes for the reports: ##### Dependencies -* As a user, I want to be able to see a list dependencies across all applications in the inventory. +* As a user, I want to be able to see a list dependencies across a selected subset applications in the inventory. (See [application selection](#selection-of-applications)) -* As a user, I want to be able to filter dependencies by applications and whether the dependency is a direct or an indirect dependency. +* As a user, I want to be able to filter dependencies by whether the dependency is a direct or an indirect dependency. -* As a user, I want to be able to see a list of dependencies shared by two or more applications in the inventory. +* As a user, I want to be able to see a list of name of the dependencies shared by two or more applications in the inventory. (See [shared dependencies](#shared-dependencies)) ##### Issues -* As a user, I want to be able to see a list of all issues generated by the analyzer for all applications in the inventory. +* As a user, I want to be able to see a list of all issues generated by the analyzer for a selected subset of applications in the inventory. (See [application selection](#selection-of-applications)) -* As a user, I want to be able to filter issues by applications, category, effort and source/target technologies. +* As a user, I want to be able to see issues that belong to one or more applications. (See [grouping](#grouping-of-issues)) -* As a user, I want to be able to use more than one filters at a time to further narrow down my search of issues. +* As a user, I want to be able to filter issues by their category, effort and name of the source / target technologies. (See [technology filters](#technology-filters)) + +* As a user, I want to be able to use filter by one or more criterias at a time to further narrow down my search of issues. (See [Filters on multiple columns](#filters-on-multiple-columns)) ##### Statistics -* As a user, I want to see total number of "mandatory" issues aggregated across all my applications from most recent analyses available. +There are two types of statistics proposed - first, statistics generated from the most recent analysis available for applications and second, statistics generated from the history of all analyses that were executed so far. +###### Based on most recent analysis data + +* As a user, I want to see total number of issues that belong to the "mandatory" category across a selected subset of applications in the inventory. -* As a user, I want to be able to see all categories of issues with their associated story points aggregated across all my applications from most recent analyses available. +* As a user, I want to be able to see all categories of issues with their associated story points across a selected subset of applications in the inventory. -* As a user, I want to be able to filter statistics generated from most recent analyses by applications. +_See [current statistics](#current-statistics)_ -* As a user, I want to be able to see trend of "mandatory" story points generated from the history of all analyses. +###### Based on historical data + +* As a user, I want to be able to see trend of story points of issues belonging to "mandatory" category generated from the history of all analyses. * As a user, I want to be able to see trend of number of issues in each category from the history of all analyses. +_See [historical data](#historical-data)_ + #### Application scope ##### Dependencies @@ -121,25 +130,25 @@ We define two scopes for the reports: * As a user, I want to be able to see a tree of dependencies so that I can distinguish between a direct and an indirect dependency. -* As a user, I want to be able to filter Java dependencies by package groups. +* As a user, I want to be able to filter Java dependencies by package groups. (See [java package groups](#filter-dependencies-by-package-groups)) ##### Issues -* As a user, I want to be able to see a list of issues for a specific application. +* As a user, I want to be able to see a list of all issues for an application. -* As a user, I want to be able to filter the issues by their category and efforts. +* As a user, I want to be able to filter issues by their category and effort. -* As a user, I want to be able to see breakdown of number of issues per category with associated story points for each category. +* As a user, I want to be able to see number of issues that belong to each category with their associated story points. -* As a user, I want to be able to see breakdown of "mandatory" issues by effort with associated story points for each level of effort. +* As a user, I want to be able that belong to "mandatory" category broken down by their effort with associated story points for each level of effort. * As a user, I want to be able to see number of issues generated per Java package. ###### Facts -* As a user, I want to be able to see all tags generated for the application including categories of tags created. +* As a user, I want to be able to see all tags generated for the application by the analyzer. -* As a user, I want to be able to filter tags by categories (tag types). +* As a user, I want to be able to filter tags created by the analyzer by categories (tag types). * As a user, I want to be able to see Enterprise Java Beans in an application. @@ -152,14 +161,38 @@ We define two scopes for the reports: ### Implementation Details/Notes/Constraints -#### Multiple Filters +#### Selection of applications + +Since there could be thousands of applications in the inventory, displaying all issues / dependencies for all applications in the inventory might not be ideal for user experience. In this enhancement, we are proposing that the users select a subset of applications via a separate filter for which they want to see the list of issues or dependencies. They can also select all applications, but we want that to be the choice of the user. + +#### Grouping of issues + +At the portfolio level, there's value in displaying impact of an issue or dependency across their portfolio. For the report, it translates into an ability to show distinct issues grouped by applications. Looking at an issue or a dependency, the user needs to be able to see how many applications have the same issue or use the same dependency. + +#### Shared Dependencies -One or more filters can be combined together to form complex searches. When using multiple filters, logical AND will be implied. In the future, we can probably expand the scope to have logical ORs in the filters. But right now, it's out of scope. We do not intend to support advanced operations like ANY, IN, etc. +When finding dependencies between two or more applications, it is implied that the dependencies will only be matched using their names. Note that dependencies have more fields than names such as versions, SHAs etc. -#### Filter dependencies by Java package groups +#### Technology filters -From analyzers perspective, Name field of a dependency would have fully qualified name for the dependency. It makes the most sense to have a generic "Name" field to accomodate all different kinds of dependencies out there for different technologies. As a result, implementing a filter based on Java package group names implies a full text search within names of dependencies. +Technologies are modelled as name of the technology along with a range of versions of the technologies, both being string values. In this enhancement, the proposed filter is based only on the name of the technology, and does not filter on version of the technology. + +#### Filters on multiple columns + +One or more columns can be combined together to form complex searches. When filtering by multiple columns, logical AND between different types of columns is implied. Within the same type of columns, however, selecting multiple values implies a logical OR. For instance, when I select "mandatory" for the category column, and "java" and "golang" for target technology, it is implied that a list of issues with "mandatory" category AND with target technologies "java" OR "golang" will be returned. + +#### Filter dependencies by Package Groups + +From analyzers perspective, Name field of a dependency would have fully qualified name for the dependency. It makes the most sense to have a generic "Name" field to accomodate all different kinds of dependencies out there for different technologies. As a result, implementing a filter based on Java package group names implies a full text search within names of dependencies. + +#### Current statistics + +It is possible that the analyses aren't available for all applications in the inventory. When selecting applications to generate statistics, we are only considering applications for which analyses data are available. #### Historical data -Contents of the dynamic report are generated from most recent analysis data except for "trends". For trends, we want to store the computed statistics of the analyses and not the entire output. We want to limit the data points we store. But we are not defining a limit on the period of time for which the data stays. +Trends are generated from high level statistics of all analyses that happened so far. We want to store the computed statistics of every analysis and not the entire output. We want to limit the data points we store. But we are not defining a limit on the period of time for which the data stays. In this enhancement, we are saying all of the data from day 1 is available. + +#### Tags + +In this enhancement, we have referred to tags as a part of Facts. From Hub's perspective, they are really just tags that currently exist. We don't intend to introduce a new concept. It's just a way of categorizing information into three pillars of data specific to an application. The ask is to be able see tags that were reported by the analyzer. Whether to include the existing tags created by the users in there is open for discussion. From da4450e210367d3d3f3c4d5a9009217190e27bf6 Mon Sep 17 00:00:00 2001 From: Pranav Gaikwad Date: Thu, 19 Oct 2023 14:46:09 -0400 Subject: [PATCH 3/3] :bug: update Signed-off-by: Pranav Gaikwad --- enhancements/dynamic-reports/README.md | 74 +++++--------------- enhancements/dynamic-reports/components.png | Bin 7426 -> 0 bytes 2 files changed, 16 insertions(+), 58 deletions(-) delete mode 100644 enhancements/dynamic-reports/components.png diff --git a/enhancements/dynamic-reports/README.md b/enhancements/dynamic-reports/README.md index d33b31d1..b7b6df77 100644 --- a/enhancements/dynamic-reports/README.md +++ b/enhancements/dynamic-reports/README.md @@ -35,11 +35,7 @@ We do not intend to discuss technical details in this enhancement. More enhancem ## Proposal -The three main components of the dynamic reports we are proposing are Issues, Dependencies and Facts. - -Issues and Dependencies are the primary components that will be aggregated over multiple applications, whereas Facts are specific information showed only in the context of a specific application. Note that the analyzers create data pertaining to all three components for one application at a time. - -![components.png](./components.png) +The two main components of the dynamic reports we are proposing are Issues, and Dependencies. An issue indicates a problem in the source code that needs to be solved for successful modernization / migration. ### Issues @@ -64,17 +60,6 @@ Analyzers output dependencies for an application with each dependency having fol * Indirect: Whether the dependency is indirect. * Type: Type of the dependency. -### Facts - -Facts are additional application specific data generated by the analyzers. Depending upon application technology, different analyzers (providers) - will generate different type of data for an application. The application facts will be generated from this information. Examples of application facts for a Java application are: - - Enterprise Java Beans reports - - Java Persistent API usage reports - - Spring Beans reports - - Hibernate session usage - -Facts are data that don't necessarily fit into the notion of "issues" or "dependencies". Since the data types for facts are arbitrary, we do not envision aggregating this data at the portfolio level. Facts will only be presented in the context of an application. Filtering / querying application facts will not be possible due to the nature of the data. - ### User Stories We define two scopes for the reports: @@ -103,25 +88,6 @@ We define two scopes for the reports: * As a user, I want to be able to use filter by one or more criterias at a time to further narrow down my search of issues. (See [Filters on multiple columns](#filters-on-multiple-columns)) -##### Statistics - -There are two types of statistics proposed - first, statistics generated from the most recent analysis available for applications and second, statistics generated from the history of all analyses that were executed so far. -###### Based on most recent analysis data - -* As a user, I want to see total number of issues that belong to the "mandatory" category across a selected subset of applications in the inventory. - -* As a user, I want to be able to see all categories of issues with their associated story points across a selected subset of applications in the inventory. - -_See [current statistics](#current-statistics)_ - -###### Based on historical data - -* As a user, I want to be able to see trend of story points of issues belonging to "mandatory" category generated from the history of all analyses. - -* As a user, I want to be able to see trend of number of issues in each category from the history of all analyses. - -_See [historical data](#historical-data)_ - #### Application scope ##### Dependencies @@ -142,23 +108,6 @@ _See [historical data](#historical-data)_ * As a user, I want to be able that belong to "mandatory" category broken down by their effort with associated story points for each level of effort. -* As a user, I want to be able to see number of issues generated per Java package. - -###### Facts - -* As a user, I want to be able to see all tags generated for the application by the analyzer. - -* As a user, I want to be able to filter tags created by the analyzer by categories (tag types). - -* As a user, I want to be able to see Enterprise Java Beans in an application. - -* As a user, I want to be able to see Java Persistence API usage with details including persistent units, entities and queries. - -* As a user, I want to be able to see a list of Spring Beans in an application with details including Bean Name and Class. - -* As a user, I want to be able to see Hibernate session factories and entities in an application. - - ### Implementation Details/Notes/Constraints #### Selection of applications @@ -185,14 +134,23 @@ One or more columns can be combined together to form complex searches. When filt From analyzers perspective, Name field of a dependency would have fully qualified name for the dependency. It makes the most sense to have a generic "Name" field to accomodate all different kinds of dependencies out there for different technologies. As a result, implementing a filter based on Java package group names implies a full text search within names of dependencies. -#### Current statistics +### Descoped to future + +##### Statistics + +There are two types of statistics proposed - first, statistics generated from the most recent analysis available for applications and second, statistics generated from the history of all analyses that were executed so far. +###### Based on most recent analysis data -It is possible that the analyses aren't available for all applications in the inventory. When selecting applications to generate statistics, we are only considering applications for which analyses data are available. +* As a user, I want to see total number of issues that belong to the "mandatory" category across a selected subset of applications in the inventory. -#### Historical data +* As a user, I want to be able to see all categories of issues with their associated story points across a selected subset of applications in the inventory. -Trends are generated from high level statistics of all analyses that happened so far. We want to store the computed statistics of every analysis and not the entire output. We want to limit the data points we store. But we are not defining a limit on the period of time for which the data stays. In this enhancement, we are saying all of the data from day 1 is available. +_See [current statistics](#current-statistics)_ -#### Tags +###### Based on historical data + +* As a user, I want to be able to see trend of story points of issues belonging to "mandatory" category generated from the history of all analyses. + +* As a user, I want to be able to see trend of number of issues in each category from the history of all analyses. -In this enhancement, we have referred to tags as a part of Facts. From Hub's perspective, they are really just tags that currently exist. We don't intend to introduce a new concept. It's just a way of categorizing information into three pillars of data specific to an application. The ask is to be able see tags that were reported by the analyzer. Whether to include the existing tags created by the users in there is open for discussion. +_See [historical data](#historical-data)_ \ No newline at end of file diff --git a/enhancements/dynamic-reports/components.png b/enhancements/dynamic-reports/components.png deleted file mode 100644 index b0315c1ddff9aa115186ac1a1210c52105bbd737..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7426 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