From 7c6bd53672ae1f98b6ab8e49f60b1939f3ea0771 Mon Sep 17 00:00:00 2001
From: sandhami <138873170+sandhami@users.noreply.github.com>
Date: Tue, 13 May 2025 10:31:52 +0530
Subject: [PATCH 01/55] Update pom.xml
Signed-off-by: sandhami <138873170+sandhami@users.noreply.github.com>
---
pom.xml | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/pom.xml b/pom.xml
index 183fd850c..de3eb42e1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,8 +20,14 @@
4.0.0
com.publicissapient.kpidashboard
processors
- 6.0.0-SNAPSHOT
+ 13.1.0-SNAPSHOT
pom
+
+ scm:git:https://github.com/PublicisSapient/knowhow-processor.git
+ scm:git:https://github.com/PublicisSapient/knowhow-processor.git
+ 4.6.1
+ https://github.com/PublicisSapient/knowhow-processor.git
+
${project.basedir}/../../target/jacoco.exec
**com/publicissapient/kpidashboard/**/*Application.java,
From 794c5939f69b6cf4c8d43b559b6ca60b7c9c4bd5 Mon Sep 17 00:00:00 2001
From: rapkalya
Date: Tue, 13 May 2025 05:16:56 +0000
Subject: [PATCH 02/55] [maven-release-plugin] prepare release 13.1.1
---
argocd/pom.xml | 4 ++--
azure-boards/pom.xml | 4 ++--
azure-pipeline/pom.xml | 4 ++--
azure-repo/pom.xml | 4 ++--
bamboo/pom.xml | 4 ++--
bitbucket/pom.xml | 4 ++--
github-action/pom.xml | 4 ++--
github/pom.xml | 4 ++--
gitlab/pom.xml | 4 ++--
jenkins/pom.xml | 4 ++--
jira-xray-zephyr-squad/pom.xml | 4 ++--
jira-zephyr-scale/pom.xml | 4 ++--
jira/pom.xml | 4 ++--
pom.xml | 4 ++--
sonar/pom.xml | 4 ++--
teamcity/pom.xml | 4 ++--
16 files changed, 32 insertions(+), 32 deletions(-)
diff --git a/argocd/pom.xml b/argocd/pom.xml
index ad6bafa43..42cdfede1 100644
--- a/argocd/pom.xml
+++ b/argocd/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
argocd-processor
- 13.1.0-SNAPSHOT
+ 13.1.1
jar
ArgoCD Processor
- 4.6.1
+ 13.1.1
17
diff --git a/azure-boards/pom.xml b/azure-boards/pom.xml
index 987d567a2..d12ad97e6 100644
--- a/azure-boards/pom.xml
+++ b/azure-boards/pom.xml
@@ -26,10 +26,10 @@
com.publicissapient.kpidashboard
azure-processor
- 13.1.0-SNAPSHOT
+ 13.1.1
Azure processor fetches data from Azure api
- 4.6.1
+ 13.1.1
17
diff --git a/azure-pipeline/pom.xml b/azure-pipeline/pom.xml
index 585952cf6..e42170f75 100644
--- a/azure-pipeline/pom.xml
+++ b/azure-pipeline/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
azurepipeline-processor
- 13.1.0-SNAPSHOT
+ 13.1.1
jar
Azure Pipeline Build Processor Microservice
- 4.6.1
+ 13.1.1
17
diff --git a/azure-repo/pom.xml b/azure-repo/pom.xml
index 7f995b110..dfe6a24e5 100644
--- a/azure-repo/pom.xml
+++ b/azure-repo/pom.xml
@@ -19,11 +19,11 @@
com.publicissapient.kpidashboard
azurerepo-processor
- 13.1.0-SNAPSHOT
+ 13.1.1
jar
Azure Repo processor service
- 4.6.1
+ 13.1.1
true
diff --git a/bamboo/pom.xml b/bamboo/pom.xml
index d5df2c228..891ffb163 100644
--- a/bamboo/pom.xml
+++ b/bamboo/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
bamboo-processor
- 13.1.0-SNAPSHOT
+ 13.1.1
jar
bamboo processor
- 4.6.1
+ 13.1.1
17
diff --git a/bitbucket/pom.xml b/bitbucket/pom.xml
index 9c06352b8..bf3baa48d 100644
--- a/bitbucket/pom.xml
+++ b/bitbucket/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
bitbucket-processor
- 13.1.0-SNAPSHOT
+ 13.1.1
jar
Bitbucket processor service
- 4.6.1
+ 13.1.1
true
diff --git a/github-action/pom.xml b/github-action/pom.xml
index b86851164..107c248ea 100644
--- a/github-action/pom.xml
+++ b/github-action/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
githubaction-processor
- 13.1.0-SNAPSHOT
+ 13.1.1
jar
Github Actions processor service
- 4.6.1
+ 13.1.1
17
diff --git a/github/pom.xml b/github/pom.xml
index 238ba4386..5d2b3fd5f 100644
--- a/github/pom.xml
+++ b/github/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
github-processor
- 13.1.0-SNAPSHOT
+ 13.1.1
jar
Github processor service
- 4.6.1
+ 13.1.1
17
diff --git a/gitlab/pom.xml b/gitlab/pom.xml
index cae4c2faa..2573e0de5 100644
--- a/gitlab/pom.xml
+++ b/gitlab/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
gitlab-processor
- 13.1.0-SNAPSHOT
+ 13.1.1
jar
GitLab processor service
- 4.6.1
+ 13.1.1
true
diff --git a/jenkins/pom.xml b/jenkins/pom.xml
index 9f6cc6f26..41218a408 100644
--- a/jenkins/pom.xml
+++ b/jenkins/pom.xml
@@ -19,11 +19,11 @@
com.publicissapient.kpidashboard
jenkins-processor
- 13.1.0-SNAPSHOT
+ 13.1.1
jar
Jenkins Build Processor Microservice
- 4.6.1
+ 13.1.1
17
diff --git a/jira-xray-zephyr-squad/pom.xml b/jira-xray-zephyr-squad/pom.xml
index adfe128d7..352ab0a1e 100644
--- a/jira-xray-zephyr-squad/pom.xml
+++ b/jira-xray-zephyr-squad/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
jiratest-processor
- 13.1.0-SNAPSHOT
+ 13.1.1
jar
Jira Test Processor Microservice
- 4.6.1
+ 13.1.1
UTF-8
diff --git a/jira-zephyr-scale/pom.xml b/jira-zephyr-scale/pom.xml
index f0206d471..7943619c6 100644
--- a/jira-zephyr-scale/pom.xml
+++ b/jira-zephyr-scale/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
zephyr-processor
- 13.1.0-SNAPSHOT
+ 13.1.1
jar
Zephyr Processor Microservice
- 4.6.1
+ 13.1.1
UTF-8
diff --git a/jira/pom.xml b/jira/pom.xml
index 55d686e68..35d791c07 100644
--- a/jira/pom.xml
+++ b/jira/pom.xml
@@ -19,10 +19,10 @@
com.publicissapient.kpidashboard
jira-processor
- 13.1.0-SNAPSHOT
+ 13.1.1
Jira processor fetches data from JIRA api
- 4.6.1
+ 13.1.1
17
diff --git a/pom.xml b/pom.xml
index de3eb42e1..54dc881d2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,12 +20,12 @@
4.0.0
com.publicissapient.kpidashboard
processors
- 13.1.0-SNAPSHOT
+ 13.1.1
pom
scm:git:https://github.com/PublicisSapient/knowhow-processor.git
scm:git:https://github.com/PublicisSapient/knowhow-processor.git
- 4.6.1
+ 13.1.1
https://github.com/PublicisSapient/knowhow-processor.git
diff --git a/sonar/pom.xml b/sonar/pom.xml
index 1f88feaba..d7b4725fc 100644
--- a/sonar/pom.xml
+++ b/sonar/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
sonar-processor
- 13.1.0-SNAPSHOT
+ 13.1.1
jar
CodeQuality Processor Microservice
- 4.6.1
+ 13.1.1
17
diff --git a/teamcity/pom.xml b/teamcity/pom.xml
index 14092322b..679aa11bd 100644
--- a/teamcity/pom.xml
+++ b/teamcity/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
teamcity-processor
- 13.1.0-SNAPSHOT
+ 13.1.1
jar
Teamcity Build Processor Microservice
- 4.6.1
+ 13.1.1
17
From b3af31b6bd1f56aeed790748f8784ff6cf498d22 Mon Sep 17 00:00:00 2001
From: rapkalya
Date: Tue, 13 May 2025 05:16:57 +0000
Subject: [PATCH 03/55] [maven-release-plugin] prepare for next development
iteration
---
argocd/pom.xml | 4 ++--
azure-boards/pom.xml | 4 ++--
azure-pipeline/pom.xml | 4 ++--
azure-repo/pom.xml | 4 ++--
bamboo/pom.xml | 4 ++--
bitbucket/pom.xml | 4 ++--
github-action/pom.xml | 4 ++--
github/pom.xml | 4 ++--
gitlab/pom.xml | 4 ++--
jenkins/pom.xml | 4 ++--
jira-xray-zephyr-squad/pom.xml | 4 ++--
jira-zephyr-scale/pom.xml | 4 ++--
jira/pom.xml | 4 ++--
pom.xml | 4 ++--
sonar/pom.xml | 4 ++--
teamcity/pom.xml | 4 ++--
16 files changed, 32 insertions(+), 32 deletions(-)
diff --git a/argocd/pom.xml b/argocd/pom.xml
index 42cdfede1..1e0914e42 100644
--- a/argocd/pom.xml
+++ b/argocd/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
argocd-processor
- 13.1.1
+ 13.1.1-SNAPSHOT
jar
ArgoCD Processor
- 13.1.1
+ 4.6.1
17
diff --git a/azure-boards/pom.xml b/azure-boards/pom.xml
index d12ad97e6..8ce252b05 100644
--- a/azure-boards/pom.xml
+++ b/azure-boards/pom.xml
@@ -26,10 +26,10 @@
com.publicissapient.kpidashboard
azure-processor
- 13.1.1
+ 13.1.1-SNAPSHOT
Azure processor fetches data from Azure api
- 13.1.1
+ 4.6.1
17
diff --git a/azure-pipeline/pom.xml b/azure-pipeline/pom.xml
index e42170f75..cbfec05c2 100644
--- a/azure-pipeline/pom.xml
+++ b/azure-pipeline/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
azurepipeline-processor
- 13.1.1
+ 13.1.1-SNAPSHOT
jar
Azure Pipeline Build Processor Microservice
- 13.1.1
+ 4.6.1
17
diff --git a/azure-repo/pom.xml b/azure-repo/pom.xml
index dfe6a24e5..6fe6ebe65 100644
--- a/azure-repo/pom.xml
+++ b/azure-repo/pom.xml
@@ -19,11 +19,11 @@
com.publicissapient.kpidashboard
azurerepo-processor
- 13.1.1
+ 13.1.1-SNAPSHOT
jar
Azure Repo processor service
- 13.1.1
+ 4.6.1
true
diff --git a/bamboo/pom.xml b/bamboo/pom.xml
index 891ffb163..07ee534b6 100644
--- a/bamboo/pom.xml
+++ b/bamboo/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
bamboo-processor
- 13.1.1
+ 13.1.1-SNAPSHOT
jar
bamboo processor
- 13.1.1
+ 4.6.1
17
diff --git a/bitbucket/pom.xml b/bitbucket/pom.xml
index bf3baa48d..64c154248 100644
--- a/bitbucket/pom.xml
+++ b/bitbucket/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
bitbucket-processor
- 13.1.1
+ 13.1.1-SNAPSHOT
jar
Bitbucket processor service
- 13.1.1
+ 4.6.1
true
diff --git a/github-action/pom.xml b/github-action/pom.xml
index 107c248ea..5928875e9 100644
--- a/github-action/pom.xml
+++ b/github-action/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
githubaction-processor
- 13.1.1
+ 13.1.1-SNAPSHOT
jar
Github Actions processor service
- 13.1.1
+ 4.6.1
17
diff --git a/github/pom.xml b/github/pom.xml
index 5d2b3fd5f..a95e488cb 100644
--- a/github/pom.xml
+++ b/github/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
github-processor
- 13.1.1
+ 13.1.1-SNAPSHOT
jar
Github processor service
- 13.1.1
+ 4.6.1
17
diff --git a/gitlab/pom.xml b/gitlab/pom.xml
index 2573e0de5..4fe9dc6c8 100644
--- a/gitlab/pom.xml
+++ b/gitlab/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
gitlab-processor
- 13.1.1
+ 13.1.1-SNAPSHOT
jar
GitLab processor service
- 13.1.1
+ 4.6.1
true
diff --git a/jenkins/pom.xml b/jenkins/pom.xml
index 41218a408..e1563759a 100644
--- a/jenkins/pom.xml
+++ b/jenkins/pom.xml
@@ -19,11 +19,11 @@
com.publicissapient.kpidashboard
jenkins-processor
- 13.1.1
+ 13.1.1-SNAPSHOT
jar
Jenkins Build Processor Microservice
- 13.1.1
+ 4.6.1
17
diff --git a/jira-xray-zephyr-squad/pom.xml b/jira-xray-zephyr-squad/pom.xml
index 352ab0a1e..b8008e4cd 100644
--- a/jira-xray-zephyr-squad/pom.xml
+++ b/jira-xray-zephyr-squad/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
jiratest-processor
- 13.1.1
+ 13.1.1-SNAPSHOT
jar
Jira Test Processor Microservice
- 13.1.1
+ 4.6.1
UTF-8
diff --git a/jira-zephyr-scale/pom.xml b/jira-zephyr-scale/pom.xml
index 7943619c6..5fe823831 100644
--- a/jira-zephyr-scale/pom.xml
+++ b/jira-zephyr-scale/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
zephyr-processor
- 13.1.1
+ 13.1.1-SNAPSHOT
jar
Zephyr Processor Microservice
- 13.1.1
+ 4.6.1
UTF-8
diff --git a/jira/pom.xml b/jira/pom.xml
index 35d791c07..3e3fc4fc5 100644
--- a/jira/pom.xml
+++ b/jira/pom.xml
@@ -19,10 +19,10 @@
com.publicissapient.kpidashboard
jira-processor
- 13.1.1
+ 13.1.1-SNAPSHOT
Jira processor fetches data from JIRA api
- 13.1.1
+ 4.6.1
17
diff --git a/pom.xml b/pom.xml
index 54dc881d2..789b7cea6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,12 +20,12 @@
4.0.0
com.publicissapient.kpidashboard
processors
- 13.1.1
+ 13.1.1-SNAPSHOT
pom
scm:git:https://github.com/PublicisSapient/knowhow-processor.git
scm:git:https://github.com/PublicisSapient/knowhow-processor.git
- 13.1.1
+ 4.6.1
https://github.com/PublicisSapient/knowhow-processor.git
diff --git a/sonar/pom.xml b/sonar/pom.xml
index d7b4725fc..765ec3a43 100644
--- a/sonar/pom.xml
+++ b/sonar/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
sonar-processor
- 13.1.1
+ 13.1.1-SNAPSHOT
jar
CodeQuality Processor Microservice
- 13.1.1
+ 4.6.1
17
diff --git a/teamcity/pom.xml b/teamcity/pom.xml
index 679aa11bd..371893490 100644
--- a/teamcity/pom.xml
+++ b/teamcity/pom.xml
@@ -26,11 +26,11 @@
com.publicissapient.kpidashboard
teamcity-processor
- 13.1.1
+ 13.1.1-SNAPSHOT
jar
Teamcity Build Processor Microservice
- 13.1.1
+ 4.6.1
17
From 3053a420e1eecd2a37fa2d57b726dbae46747819 Mon Sep 17 00:00:00 2001
From: sandhami <138873170+sandhami@users.noreply.github.com>
Date: Tue, 13 May 2025 12:51:31 +0530
Subject: [PATCH 04/55] Update pom.xml
Signed-off-by: sandhami <138873170+sandhami@users.noreply.github.com>
---
argocd/pom.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/argocd/pom.xml b/argocd/pom.xml
index 1e0914e42..80cbe85f6 100644
--- a/argocd/pom.xml
+++ b/argocd/pom.xml
@@ -55,7 +55,7 @@
com.publicissapient.kpidashboard
common
- ${project.version}
+ 13.1.0-SNAPSHOT
org.projectlombok
From bda1f6c0fccb8a77608d06361d12f5739882a2d3 Mon Sep 17 00:00:00 2001
From: sandhami <138873170+sandhami@users.noreply.github.com>
Date: Tue, 13 May 2025 12:55:21 +0530
Subject: [PATCH 05/55] ${project.version} replaced with 13.1.0-SNAPSHOT
---
azure-boards/pom.xml | 4 ++--
azure-pipeline/pom.xml | 2 +-
azure-repo/pom.xml | 2 +-
bamboo/pom.xml | 2 +-
bitbucket/pom.xml | 2 +-
github-action/pom.xml | 2 +-
github/pom.xml | 2 +-
gitlab/pom.xml | 2 +-
jenkins/pom.xml | 2 +-
jira-xray-zephyr-squad/pom.xml | 2 +-
jira-zephyr-scale/pom.xml | 2 +-
jira/pom.xml | 4 ++--
sonar/pom.xml | 2 +-
teamcity/pom.xml | 2 +-
14 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/azure-boards/pom.xml b/azure-boards/pom.xml
index 8ce252b05..56d3d6224 100644
--- a/azure-boards/pom.xml
+++ b/azure-boards/pom.xml
@@ -57,7 +57,7 @@
com.publicissapient.kpidashboard
common
- ${project.version}
+ 13.1.0-SNAPSHOT
compile
@@ -352,7 +352,7 @@
Dockerfile
azure-board-processor
- ${project.version}
+ 13.1.0-SNAPSHOT
target/${project.build.finalName}-exec.jar
diff --git a/azure-pipeline/pom.xml b/azure-pipeline/pom.xml
index cbfec05c2..e1d31db30 100644
--- a/azure-pipeline/pom.xml
+++ b/azure-pipeline/pom.xml
@@ -59,7 +59,7 @@
com.publicissapient.kpidashboard
common
- ${project.version}
+ 13.1.0-SNAPSHOT
ch.qos.logback
diff --git a/azure-repo/pom.xml b/azure-repo/pom.xml
index 6fe6ebe65..9f8e16ee6 100644
--- a/azure-repo/pom.xml
+++ b/azure-repo/pom.xml
@@ -50,7 +50,7 @@
com.publicissapient.kpidashboard
common
- ${project.version}
+ 13.1.0-SNAPSHOT
ch.qos.logback
diff --git a/bamboo/pom.xml b/bamboo/pom.xml
index 07ee534b6..40efa96d8 100644
--- a/bamboo/pom.xml
+++ b/bamboo/pom.xml
@@ -61,7 +61,7 @@
com.publicissapient.kpidashboard
common
- ${project.version}
+ 13.1.0-SNAPSHOT
ch.qos.logback
diff --git a/bitbucket/pom.xml b/bitbucket/pom.xml
index 64c154248..23658574d 100644
--- a/bitbucket/pom.xml
+++ b/bitbucket/pom.xml
@@ -57,7 +57,7 @@
com.publicissapient.kpidashboard
common
- ${project.version}
+ 13.1.0-SNAPSHOT
ch.qos.logback
diff --git a/github-action/pom.xml b/github-action/pom.xml
index 5928875e9..4f1067d50 100644
--- a/github-action/pom.xml
+++ b/github-action/pom.xml
@@ -55,7 +55,7 @@
com.publicissapient.kpidashboard
common
- ${project.version}
+ 13.1.0-SNAPSHOT
ch.qos.logback
diff --git a/github/pom.xml b/github/pom.xml
index a95e488cb..649590c35 100644
--- a/github/pom.xml
+++ b/github/pom.xml
@@ -55,7 +55,7 @@
com.publicissapient.kpidashboard
common
- ${project.version}
+ 13.1.0-SNAPSHOT
ch.qos.logback
diff --git a/gitlab/pom.xml b/gitlab/pom.xml
index 4fe9dc6c8..ae687d3f6 100644
--- a/gitlab/pom.xml
+++ b/gitlab/pom.xml
@@ -56,7 +56,7 @@
com.publicissapient.kpidashboard
common
- ${project.version}
+ 13.1.0-SNAPSHOT
ch.qos.logback
diff --git a/jenkins/pom.xml b/jenkins/pom.xml
index e1563759a..eca96b7dd 100644
--- a/jenkins/pom.xml
+++ b/jenkins/pom.xml
@@ -51,7 +51,7 @@
com.publicissapient.kpidashboard
common
- ${project.version}
+ 13.1.0-SNAPSHOT
ch.qos.logback
diff --git a/jira-xray-zephyr-squad/pom.xml b/jira-xray-zephyr-squad/pom.xml
index b8008e4cd..4e04a0860 100644
--- a/jira-xray-zephyr-squad/pom.xml
+++ b/jira-xray-zephyr-squad/pom.xml
@@ -63,7 +63,7 @@
com.publicissapient.kpidashboard
common
- ${project.version}
+ 13.1.0-SNAPSHOT
compile
diff --git a/jira-zephyr-scale/pom.xml b/jira-zephyr-scale/pom.xml
index 5fe823831..d05a07bda 100644
--- a/jira-zephyr-scale/pom.xml
+++ b/jira-zephyr-scale/pom.xml
@@ -56,7 +56,7 @@
com.publicissapient.kpidashboard
common
- ${project.version}
+ 13.1.0-SNAPSHOT
ch.qos.logback
diff --git a/jira/pom.xml b/jira/pom.xml
index 3e3fc4fc5..8cdff53ac 100644
--- a/jira/pom.xml
+++ b/jira/pom.xml
@@ -93,7 +93,7 @@
com.publicissapient.kpidashboard
common
- ${project.version}
+ 13.1.0-SNAPSHOT
compile
@@ -526,7 +526,7 @@
Dockerfile
${final.name}
- ${project.version}
+ 13.1.0-SNAPSHOT
target/${project.build.finalName}-exec.jar
diff --git a/sonar/pom.xml b/sonar/pom.xml
index 765ec3a43..cb5f3e73c 100644
--- a/sonar/pom.xml
+++ b/sonar/pom.xml
@@ -55,7 +55,7 @@
com.publicissapient.kpidashboard
common
- ${project.version}
+ 13.1.0-SNAPSHOT
ch.qos.logback
diff --git a/teamcity/pom.xml b/teamcity/pom.xml
index 371893490..9d32ff854 100644
--- a/teamcity/pom.xml
+++ b/teamcity/pom.xml
@@ -72,7 +72,7 @@
com.publicissapient.kpidashboard
common
- ${project.version}
+ 13.1.0-SNAPSHOT
ch.qos.logback
From 10c3bccfacb165796422dd9723436cadbe354938 Mon Sep 17 00:00:00 2001
From: sandhami <138873170+sandhami@users.noreply.github.com>
Date: Tue, 13 May 2025 13:03:11 +0530
Subject: [PATCH 06/55] pom updated
---
azure-boards/pom.xml | 2 +-
jira/pom.xml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/azure-boards/pom.xml b/azure-boards/pom.xml
index 56d3d6224..d48aafaba 100644
--- a/azure-boards/pom.xml
+++ b/azure-boards/pom.xml
@@ -352,7 +352,7 @@
Dockerfile
azure-board-processor
- 13.1.0-SNAPSHOT
+ ${project.version}
target/${project.build.finalName}-exec.jar
diff --git a/jira/pom.xml b/jira/pom.xml
index 8cdff53ac..0fca08288 100644
--- a/jira/pom.xml
+++ b/jira/pom.xml
@@ -526,7 +526,7 @@
Dockerfile
${final.name}
- 13.1.0-SNAPSHOT
+ ${project.version}
target/${project.build.finalName}-exec.jar
From e1f845705205dcaf3df54b36bca61ffa1e94afe1 Mon Sep 17 00:00:00 2001
From: girpatha
Date: Wed, 14 May 2025 10:23:50 +0530
Subject: [PATCH 07/55] DTS-46390: Rally Implementation initial version
---
rally/Dockerfile | 49 +
rally/pom.xml | 569 ++++++++++
.../rally/RallyProcessorApplication.java | 71 ++
.../aspect/PerformanceLoggingAspect.java | 60 +
.../rally/aspect/TrackExecutionTime.java | 31 +
.../rally/cache/CacheClearingMechanism.java | 54 +
.../cache/RallyProcessorCacheEvictor.java | 126 +++
.../config/FetchProjectConfiguration.java | 32 +
.../config/FetchProjectConfigurationImpl.java | 161 +++
.../rally/config/KafkaProducerConfig.java | 35 +
.../rally/config/MongoDBConfig.java | 50 +
.../rally/config/RallyProcessorConfig.java | 81 ++
.../rally/config/WebSecurityConfig.java | 36 +
.../rally/constant/RallyConstants.java | 122 ++
.../rally/controller/JobController.java | 292 +++++
.../rally/helper/AdditionalFilterHelper.java | 206 ++++
.../rally/helper/BuilderFactory.java | 36 +
.../rally/helper/RallyHelper.java | 190 ++++
.../rally/helper/ReaderRetryHelper.java | 51 +
.../rally/jobs/RallyProcessorJob.java | 171 +++
.../listener/JiraIssueJqlWriterListener.java | 149 +++
.../listener/JiraIssueSprintJobListener.java | 95 ++
.../rally/listener/JobListenerKanban.java | 232 ++++
.../rally/listener/JobListenerScrum.java | 269 +++++
.../listener/JobStepProgressListener.java | 115 ++
.../rally/model/CompositeResult.java | 43 +
.../kpidashboard/rally/model/Defect.java | 42 +
.../rally/model/HierarchicalRequirement.java | 60 +
.../kpidashboard/rally/model/Iteration.java | 65 ++
.../rally/model/IterationResponse.java | 34 +
.../kpidashboard/rally/model/JiraInfo.java | 38 +
.../rally/model/JiraIssueMetadata.java | 34 +
.../kpidashboard/rally/model/Owner.java | 40 +
.../kpidashboard/rally/model/Project.java | 34 +
.../rally/model/ProjectConfFieldMapping.java | 55 +
.../kpidashboard/rally/model/QueryResult.java | 36 +
.../model/RallyAllowedValuesResponse.java | 70 ++
.../rally/model/RallyArtifact.java | 20 +
.../rally/model/RallyChangelogGroup.java | 29 +
.../rally/model/RallyIssueField.java | 53 +
.../rally/model/RallyProcessor.java | 48 +
.../rally/model/RallyReleaseResponse.java | 64 ++
.../rally/model/RallyResponse.java | 31 +
.../rally/model/RallyStateResponse.java | 73 ++
.../rally/model/RallyToolConfig.java | 52 +
.../model/RallyTypeDefinitionResponse.java | 48 +
.../kpidashboard/rally/model/ReadData.java | 34 +
.../kpidashboard/rally/model/Release.java | 104 ++
.../rally/model/ReleaseWrapper.java | 12 +
.../kpidashboard/rally/model/Requirement.java | 17 +
.../rally/model/RevisionHistory.java | 30 +
.../kpidashboard/rally/model/Sprint.java | 38 +
.../rally/model/UserIterationCapacity.java | 30 +
.../rally/model/WorkProducts.java | 42 +
.../kpidashboard/rally/model/Workspace.java | 30 +
.../parser/CustomChangelogJsonParser.java | 46 +
.../rally/parser/CustomIssueJsonParser.java | 384 +++++++
.../parser/CustomSearchResultJsonParser.java | 52 +
.../rally/parser/CustomUserJsonParser.java | 75 ++
.../rally/parser/JsonWeakParser.java | 25 +
.../parser/JsonWeakParserForJsonObject.java | 46 +
.../rally/parser/JsonWeakParserForString.java | 33 +
.../rally/processor/IssueScrumProcessor.java | 128 +++
.../RallyIssueAccountHierarchyProcessor.java | 43 +
...llyIssueAccountHierarchyProcessorImpl.java | 188 ++++
.../RallyIssueAssigneeProcessor.java | 36 +
.../RallyIssueAssigneeProcessorImpl.java | 82 ++
.../processor/RallyIssueHistoryProcessor.java | 38 +
.../RallyIssueHistoryProcessorImpl.java | 470 ++++++++
.../rally/processor/RallyIssueProcessor.java | 44 +
.../processor/RallyIssueProcessorImpl.java | 1002 +++++++++++++++++
.../rally/processor/SprintDataProcessor.java | 46 +
.../processor/SprintDataProcessorImpl.java | 154 +++
.../rally/reader/IssueRqlReader.java | 193 ++++
.../rally/reader/IssueSprintReader.java | 139 +++
.../repository/RallyProcessorRepository.java | 28 +
.../rally/scheduler/JobScheduler.java | 104 ++
.../BearerTokenAuthenticationHandler.java | 50 +
.../rally/service/CreateMetadata.java | 33 +
.../rally/service/CreateMetadataImpl.java | 269 +++++
.../CreateRallyIssueReleaseStatus.java | 29 +
.../CreateRallyIssueReleaseStatusImpl.java | 188 ++++
.../rally/service/FetchEpicData.java | 47 +
.../rally/service/FetchEpicDataImpl.java | 172 +++
.../rally/service/FetchIssueSprint.java | 41 +
.../rally/service/FetchIssueSprintImpl.java | 229 ++++
.../rally/service/FetchScrumReleaseData.java | 40 +
.../service/FetchScrumReleaseDataImpl.java | 206 ++++
.../rally/service/FetchSprintReport.java | 81 ++
.../rally/service/FetchSprintReportImpl.java | 583 ++++++++++
.../rally/service/JiraClientService.java | 66 ++
.../rally/service/NotificationHandler.java | 160 +++
.../service/OngoingExecutionsService.java | 70 ++
.../rally/service/OutlierSprintStrategy.java | 44 +
.../service/OutlierSprintStrategyImpl.java | 155 +++
.../service/ProjectHierarchySyncService.java | 62 +
.../ProjectHierarchySyncServiceImpl.java | 127 +++
.../rally/service/RallyCommonService.java | 588 ++++++++++
.../service/SpnegoAuthenticationHandler.java | 51 +
.../ToolCredentialProviderJiraImpl.java | 33 +
.../JiraIssueReleaseStatusTasklet.java | 78 ++
.../rally/tasklet/MetaDataTasklet.java | 78 ++
.../tasklet/ScrumReleaseDataTasklet.java | 77 ++
.../rally/tasklet/SprintReportTasklet.java | 114 ++
.../tasklet/SprintScrumBoardTasklet.java | 96 ++
.../rally/util/JiraIssueClientUtil.java | 143 +++
.../rally/util/JiraProcessorUtil.java | 419 +++++++
.../rally/util/JsonParseUtil.java | 144 +++
.../rally/util/RallyProcessorUtil.java | 76 ++
.../rally/util/RallyRestClient.java | 144 +++
.../rally/writer/IssueKanbanWriter.java | 147 +++
.../rally/writer/IssueScrumWriter.java | 223 ++++
.../src/main/resources/application.properties | 134 +++
rally/src/main/resources/banner.txt | 6 +
rally/src/main/resources/logback.xml | 95 ++
.../Error_In_Rally_Processor_Template.html | 79 ++
.../Outlier_In_Rally_Processor_Template.html | 82 ++
.../aspect/TrackExecutionTimeAspectTest.java | 74 ++
.../cache/CacheClearingMechanismTest.java | 72 ++
.../helper/AdditionalFilterHelperTest.java | 134 +++
.../rally/helper/RallyHelperTest.java | 188 ++++
.../processor/IssueScrumProcessorTest.java | 138 +++
...ssueAccountHierarchyProcessorImplTest.java | 180 +++
.../RallyIssueAssigneeProcessorImplTest.java | 154 +++
.../RallyIssueHistoryProcessorImplTest.java | 152 +++
.../RallyIssueProcessorImplTest.java | 146 +++
.../rally/reader/IssueRqlReaderTest.java | 158 +++
.../rally/reader/IssueSprintReaderTest.java | 160 +++
.../rally/service/RallyCommonServiceTest.java | 176 +++
129 files changed, 15136 insertions(+)
create mode 100644 rally/Dockerfile
create mode 100644 rally/pom.xml
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/RallyProcessorApplication.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/aspect/PerformanceLoggingAspect.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/aspect/TrackExecutionTime.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/cache/CacheClearingMechanism.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/cache/RallyProcessorCacheEvictor.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/config/FetchProjectConfiguration.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/config/FetchProjectConfigurationImpl.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/config/KafkaProducerConfig.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/config/MongoDBConfig.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/config/RallyProcessorConfig.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/config/WebSecurityConfig.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/constant/RallyConstants.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/controller/JobController.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/helper/AdditionalFilterHelper.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/helper/BuilderFactory.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/helper/RallyHelper.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/helper/ReaderRetryHelper.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/jobs/RallyProcessorJob.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JiraIssueJqlWriterListener.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JiraIssueSprintJobListener.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JobListenerKanban.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JobListenerScrum.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JobStepProgressListener.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/CompositeResult.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Defect.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/HierarchicalRequirement.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Iteration.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/IterationResponse.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/JiraInfo.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/JiraIssueMetadata.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Owner.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Project.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/ProjectConfFieldMapping.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/QueryResult.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyAllowedValuesResponse.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyArtifact.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyChangelogGroup.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyIssueField.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyProcessor.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyReleaseResponse.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyResponse.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyStateResponse.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyToolConfig.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyTypeDefinitionResponse.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/ReadData.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Release.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/ReleaseWrapper.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Requirement.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RevisionHistory.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Sprint.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/UserIterationCapacity.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/WorkProducts.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Workspace.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/parser/CustomChangelogJsonParser.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/parser/CustomIssueJsonParser.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/parser/CustomSearchResultJsonParser.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/parser/CustomUserJsonParser.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/parser/JsonWeakParser.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/parser/JsonWeakParserForJsonObject.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/parser/JsonWeakParserForString.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/processor/IssueScrumProcessor.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/processor/RallyIssueAccountHierarchyProcessor.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/processor/RallyIssueAccountHierarchyProcessorImpl.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/processor/RallyIssueAssigneeProcessor.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/processor/RallyIssueAssigneeProcessorImpl.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/processor/RallyIssueHistoryProcessor.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/processor/RallyIssueHistoryProcessorImpl.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/processor/RallyIssueProcessor.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/processor/RallyIssueProcessorImpl.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/processor/SprintDataProcessor.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/processor/SprintDataProcessorImpl.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/reader/IssueRqlReader.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/reader/IssueSprintReader.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/repository/RallyProcessorRepository.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/scheduler/JobScheduler.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/BearerTokenAuthenticationHandler.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/CreateMetadata.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/CreateMetadataImpl.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/CreateRallyIssueReleaseStatus.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/CreateRallyIssueReleaseStatusImpl.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/FetchEpicData.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/FetchEpicDataImpl.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/FetchIssueSprint.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/FetchIssueSprintImpl.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/FetchScrumReleaseData.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/FetchScrumReleaseDataImpl.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/FetchSprintReport.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/FetchSprintReportImpl.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/JiraClientService.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/NotificationHandler.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/OngoingExecutionsService.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/OutlierSprintStrategy.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/OutlierSprintStrategyImpl.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/ProjectHierarchySyncService.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/ProjectHierarchySyncServiceImpl.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/RallyCommonService.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/SpnegoAuthenticationHandler.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/service/ToolCredentialProviderJiraImpl.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/tasklet/JiraIssueReleaseStatusTasklet.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/tasklet/MetaDataTasklet.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/tasklet/ScrumReleaseDataTasklet.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/tasklet/SprintReportTasklet.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/tasklet/SprintScrumBoardTasklet.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/util/JiraIssueClientUtil.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/util/JiraProcessorUtil.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/util/JsonParseUtil.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/util/RallyProcessorUtil.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/util/RallyRestClient.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/writer/IssueKanbanWriter.java
create mode 100644 rally/src/main/java/com/publicissapient/kpidashboard/rally/writer/IssueScrumWriter.java
create mode 100644 rally/src/main/resources/application.properties
create mode 100644 rally/src/main/resources/banner.txt
create mode 100644 rally/src/main/resources/logback.xml
create mode 100644 rally/src/main/resources/templates/Error_In_Rally_Processor_Template.html
create mode 100644 rally/src/main/resources/templates/Outlier_In_Rally_Processor_Template.html
create mode 100644 rally/src/test/java/com/publicissapient/kpidashboard/rally/aspect/TrackExecutionTimeAspectTest.java
create mode 100644 rally/src/test/java/com/publicissapient/kpidashboard/rally/cache/CacheClearingMechanismTest.java
create mode 100644 rally/src/test/java/com/publicissapient/kpidashboard/rally/helper/AdditionalFilterHelperTest.java
create mode 100644 rally/src/test/java/com/publicissapient/kpidashboard/rally/helper/RallyHelperTest.java
create mode 100644 rally/src/test/java/com/publicissapient/kpidashboard/rally/processor/IssueScrumProcessorTest.java
create mode 100644 rally/src/test/java/com/publicissapient/kpidashboard/rally/processor/RallyIssueAccountHierarchyProcessorImplTest.java
create mode 100644 rally/src/test/java/com/publicissapient/kpidashboard/rally/processor/RallyIssueAssigneeProcessorImplTest.java
create mode 100644 rally/src/test/java/com/publicissapient/kpidashboard/rally/processor/RallyIssueHistoryProcessorImplTest.java
create mode 100644 rally/src/test/java/com/publicissapient/kpidashboard/rally/processor/RallyIssueProcessorImplTest.java
create mode 100644 rally/src/test/java/com/publicissapient/kpidashboard/rally/reader/IssueRqlReaderTest.java
create mode 100644 rally/src/test/java/com/publicissapient/kpidashboard/rally/reader/IssueSprintReaderTest.java
create mode 100644 rally/src/test/java/com/publicissapient/kpidashboard/rally/service/RallyCommonServiceTest.java
diff --git a/rally/Dockerfile b/rally/Dockerfile
new file mode 100644
index 000000000..f5a741108
--- /dev/null
+++ b/rally/Dockerfile
@@ -0,0 +1,49 @@
+# Use a base image
+FROM amazoncorretto:17
+
+# Create a non-root user
+ARG USER=knowhowuser
+ARG UID=1000
+ARG GID=1000
+
+# Set the working directory
+WORKDIR /app
+
+# Set the ownership of the working directory to the non-root user
+RUN ln -sf /bin/bash /bin/sh \
+ && yum install -y shadow-utils \
+ && groupadd -g $GID $USER \
+ && useradd -u $UID -g $GID -m -s /bin/bash $USER \
+ && yum clean all -y
+
+# Set environment variables for volumes
+
+ENV APP_DIR="/app" \
+ PROPERTIES_DIR="/app/properties" \
+ CONFIG_LOCATION="/app/properties/rally.properties" \
+ JAVA_OPTS="" \
+ keytoolalias="myknowhow" \
+ keystorefile="/usr/lib/jvm/java-17-amazon-corretto/lib/security/cacerts"
+
+# Create the volumes
+VOLUME $PROPERTIES_DIR
+
+# Set the JAR file variable
+ARG JAR_FILE
+ADD ${JAR_FILE} $APP_DIR/rally.jar
+
+# Copy application.properties file
+ADD src/main/resources/application.properties $PROPERTIES_DIR/rally.properties
+
+# Expose port
+EXPOSE 50024
+
+# Set permissions for the JAR file
+RUN chown -R $USER:$USER /app \
+ && chmod 766 $keystorefile
+
+# Switch to the non-root user
+USER $USER:$GID
+
+# Entrypoint command
+ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar rally.jar --spring.config.location=classpath:/BOOT-INF/classes/application.properties --spring.config.additional-location=optional:file:/app/properties/rally.properties"]
diff --git a/rally/pom.xml b/rally/pom.xml
new file mode 100644
index 000000000..1f0d71272
--- /dev/null
+++ b/rally/pom.xml
@@ -0,0 +1,569 @@
+
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.2.0
+
+
+ com.publicissapient.kpidashboard
+ rally-processor
+ 12.2.0-SNAPSHOT
+
+
+ 17
+ rally-processor
+ 1.18.30
+ 4.0-beta3-atlassian-1
+ 4.2.1-atlassian-2
+ 33.0.0-jre
+
+
+
+
+ org.springframework
+ spring-web
+ 6.1.6
+
+
+ org.springframework.security
+ spring-security-core
+ 6.2.3
+
+
+
+
+
+ com.h2database
+ h2
+
+
+ org.springframework.boot
+ spring-boot-starter-batch
+
+
+ ch.qos.logback
+ logback-core
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ org.springframework.retry
+ spring-retry
+
+
+ org.springframework
+ spring-core
+
+
+
+
+
+ com.atlassian.httpclient
+ atlassian-httpclient-library
+ 3.0.4
+
+
+ org.apache.httpcomponents
+ httpasyncclient
+
+
+ org.apache.httpcomponents
+ httpclient-cache
+
+
+
+
+
+ com.publicissapient.kpidashboard
+ common
+ ${project.version}
+ compile
+
+
+ ch.qos.logback
+ logback-core
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ org.springframework
+ spring-core
+
+
+ org.springframework
+ spring-core
+
+
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.16.1
+ compile
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ provided
+
+
+ com.atlassian.jira
+ jira-rest-java-client-app
+ 5.2.0
+
+
+ org.slf4j
+ slf4j-reload4j
+
+
+ org.codehaus.jackson
+ jackson-mapper-asl
+
+
+ com.google.guava
+ guava
+
+
+ org.apache.httpcomponents
+ httpasyncclient
+
+
+ org.apache.httpcomponents
+ httpclient-cache
+
+
+ org.apache.httpcomponents
+ httpmime
+
+
+ org.codehaus.jettison
+ jettison
+
+
+ joda-time
+ joda-time
+
+
+ com.google.code.findbugs
+ jsr305
+
+
+ com.atlassian.httpclient
+ atlassian-httpclient-api
+
+
+ com.atlassian.httpclient
+ atlassian-httpclient-library
+
+
+ com.atlassian.sal
+ sal-api
+
+
+ org.springframework
+ spring-core
+
+
+
+
+ org.springframework
+ spring-core
+ 6.1.3
+
+
+ com.google.guava
+ guava
+ ${guava.version}
+
+
+ commons-codec
+ commons-codec
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-joda
+ 2.14.2
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ joda-time
+ joda-time
+
+
+
+
+
+ ch.qos.logback
+ logback-core
+ 1.4.14
+
+
+ ch.qos.logback
+ logback-classic
+ 1.4.14
+
+
+ ch.qos.logback
+ logback-core
+
+
+
+
+ org.apache.commons
+ commons-lang3
+
+
+ org.antlr
+ antlr4-runtime
+ 4.10.1
+
+
+ org.apache.commons
+ commons-collections4
+ 4.4
+
+
+ net.oauth.core
+ oauth-httpclient4
+ 20090913
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+
+
+ org.htmlunit
+ htmlunit
+ 3.9.0
+
+
+
+ com.atlassian.sal
+ sal-api
+ 5.2.0
+ compile
+
+
+ org.apache.httpcomponents.client5
+ httpclient5
+ 5.2.1
+
+
+ org.apache.httpcomponents
+ httpasyncclient
+ 4.1.5
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+
+
+ org.apache.httpcomponents
+ httpmime
+ 4.5.14
+
+
+
+ org.apache.httpcomponents
+ httpclient-cache
+ 4.5.14
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+ org.testng
+ testng
+ 7.9.0
+ test
+
+
+ org.javassist
+ javassist
+
+
+ org.webjars
+ jquery
+
+
+
+
+
+ junit
+ junit
+ test
+
+
+ org.springframework.batch
+ spring-batch-test
+ test
+
+
+ org.springframework
+ spring-core
+
+
+
+
+ org.mockito
+ mockito-core
+ 5.8.0
+ test
+
+
+ org.powermock
+ powermock-module-junit4
+ 2.0.9
+ test
+
+
+ org.objenesis
+ objenesis
+
+
+
+
+ org.hamcrest
+ hamcrest-all
+ 1.3
+ test
+
+
+ org.springframework
+ spring-test
+
+
+ org.springframework
+ spring-core
+
+
+
+
+ org.springframework.boot
+ spring-boot-test
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+
+ net.logstash.logback
+ logstash-logback-encoder
+ 7.4
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+
+
+ org.antlr
+ stringtemplate
+ 4.0.2
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+
+
+ org.springframework.metrics
+ spring-metrics
+ 0.5.1.RELEASE
+
+
+ org.springframework.boot
+ spring-boot-starter-amqp
+
+
+ org.springframework.retry
+ spring-retry
+
+
+ org.springframework
+ spring-core
+
+
+
+
+ org.springframework.amqp
+ spring-rabbit-test
+ test
+
+
+ org.mockito
+ mockito-core
+
+
+ org.springframework
+ spring-core
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-aop
+
+
+ org.springframework
+ spring-core
+
+
+
+
+ org.springframework.retry
+ spring-retry
+ 1.2.5.RELEASE
+
+
+ org.springframework
+ spring-core
+
+
+
+
+ org.powermock
+ powermock-api-mockito2
+ 2.0.9
+ test
+
+
+ org.mockito
+ mockito-core
+
+
+
+
+
+
+
+ true
+ warn
+
+
+ true
+ daily
+ warn
+
+ atlassian-public
+ https://packages.atlassian.com/maven/repository/public
+
+
+
+ ${final.name}
+
+
+ src/test/resources
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ repackage
+
+ exec
+
+
+
+
+
+ com.spotify
+ dockerfile-maven-plugin
+ 1.4.13
+
+
+ build
+
+ build
+
+ install
+
+ Dockerfile
+ ${final.name}
+ ${project.version}
+
+ target/${project.build.finalName}-exec.jar
+
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.11
+
+
+
+ prepare-agent
+
+
+
+ report
+
+ report
+
+ verify
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/RallyProcessorApplication.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/RallyProcessorApplication.java
new file mode 100644
index 000000000..132f996eb
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/RallyProcessorApplication.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.sql.DataSource;
+
+import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Scope;
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
+import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author girpatha
+ */
+@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
+@EnableCaching
+@ComponentScan(basePackages = {"com.publicissapient"})
+@EnableMongoRepositories(basePackages = {"com.publicissapient.**.repository"})
+@EnableBatchProcessing
+@EnableAsync
+@EnableScheduling
+public class RallyProcessorApplication {
+
+ private static boolean sslHostNameFlag = true;
+
+ public static void main(String[] args) {
+ HttpsURLConnection.setDefaultHostnameVerifier((s, sslSession) -> sslHostNameFlag);
+ SpringApplication.run(RallyProcessorApplication.class, args);
+ }
+
+ @Bean
+ public DataSource dataSource() {
+ return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2)
+ .addScript("classpath:org/springframework/batch/core/schema-drop-h2.sql")
+ .addScript("classpath:org/springframework/batch/core/schema-h2.sql").build();
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+}
\ No newline at end of file
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/aspect/PerformanceLoggingAspect.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/aspect/PerformanceLoggingAspect.java
new file mode 100644
index 000000000..52098e2b5
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/aspect/PerformanceLoggingAspect.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+package com.publicissapient.kpidashboard.rally.aspect;
+
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StopWatch;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author pankumar8
+ */
+@Aspect
+@Component
+@Slf4j
+@ConditionalOnExpression("${executiontime.aspect.enabled:true}")
+public class PerformanceLoggingAspect {
+
+ // AOP expression for which methods shall be intercepted
+ @Around("@annotation(com.publicissapient.kpidashboard.rally.aspect.TrackExecutionTime)")
+ public Object executionTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
+ MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
+
+ // Get intercepted method details
+ String className = methodSignature.getDeclaringType().getSimpleName();
+ String methodName = methodSignature.getName();
+
+ final StopWatch stopWatch = new StopWatch();
+
+ // Measure method execution time
+ stopWatch.start();
+ Object result = proceedingJoinPoint.proceed();
+ stopWatch.stop();
+
+ // Log method execution time
+ log.info("Execution time of " + className + "." + methodName + " :: " + stopWatch.getTotalTimeMillis() + " ms");
+
+ return result;
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/aspect/TrackExecutionTime.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/aspect/TrackExecutionTime.java
new file mode 100644
index 000000000..756c52ce9
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/aspect/TrackExecutionTime.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+package com.publicissapient.kpidashboard.rally.aspect;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author pankumar8
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TrackExecutionTime {
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/cache/CacheClearingMechanism.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/cache/CacheClearingMechanism.java
new file mode 100644
index 000000000..ed96609e1
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/cache/CacheClearingMechanism.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+package com.publicissapient.kpidashboard.rally.cache;
+
+import java.util.concurrent.CountDownLatch;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.publicissapient.kpidashboard.common.constant.CommonConstant;
+
+/**
+ * @author pankumar8
+ */
+@Component
+public class CacheClearingMechanism {
+
+ @Autowired
+ private RallyProcessorCacheEvictor rallyProcessorCacheEvictor;
+
+ private CountDownLatch latch;
+
+ public void setJobCount(int jobCount) {
+ this.latch = new CountDownLatch(jobCount);
+ }
+
+ public void signalJobCompletion() {
+ latch.countDown();
+ if (latch.getCount() == 0) {
+ clearCache();
+ }
+ }
+
+ private void clearCache() {
+ rallyProcessorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT, CommonConstant.CACHE_ACCOUNT_HIERARCHY);
+ rallyProcessorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT, CommonConstant.JIRA_KPI_CACHE);
+ rallyProcessorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT, CommonConstant.CACHE_PROJECT_KPI_DATA);
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/cache/RallyProcessorCacheEvictor.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/cache/RallyProcessorCacheEvictor.java
new file mode 100644
index 000000000..83010a9df
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/cache/RallyProcessorCacheEvictor.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.cache;
+
+import com.publicissapient.kpidashboard.rally.config.RallyProcessorConfig;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author pankumar8
+ */
+@Service
+@Slf4j
+public class RallyProcessorCacheEvictor {
+
+ @Autowired
+ private RallyProcessorConfig rallyProcessorConfig;
+
+
+ /**
+ * @param cacheEndPoint
+ * cacheEndPoint
+ * @param cacheName
+ * cacheName
+ * @return boolean
+ */
+ public boolean evictCache(String cacheEndPoint, String cacheName) {
+ boolean cleaned = false;
+ HttpHeaders headers = new HttpHeaders();
+ headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
+
+ UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(rallyProcessorConfig.getCustomApiBaseUrl());
+ uriBuilder.path("/");
+ uriBuilder.path(cacheEndPoint);
+ uriBuilder.path("/");
+ uriBuilder.path(cacheName);
+
+ HttpEntity> entity = new HttpEntity<>(headers);
+
+ RestTemplate restTemplate = new RestTemplate();
+ ResponseEntity response = null;
+ try {
+ response = restTemplate.exchange(uriBuilder.toUriString(), HttpMethod.GET, entity, String.class);
+ } catch (RuntimeException e) {
+ log.error("[RALLY-CUSTOMAPI-CACHE-EVICT]. Error while consuming rest service", e);
+ }
+
+ if (null != response && response.getStatusCode().is2xxSuccessful()) {
+ cleaned = true;
+ log.info("[RALLY-CUSTOMAPI-CACHE-EVICT]. Successfully evicted cache {}", cacheName);
+ } else {
+ log.error("[RALLY-CUSTOMAPI-CACHE-EVICT]. Error while evicting cache {}", cacheName);
+ }
+ return cleaned;
+ }
+
+ /**
+ * @param cacheEndPoint
+ * cacheEndPoint
+ * @param param1
+ * parameter 1
+ * @param param2
+ * parameter 2
+ * @return boolean
+ */
+ public boolean evictCache(String cacheEndPoint, String param1, String param2) {
+ boolean cleaned = false;
+ HttpHeaders headers = new HttpHeaders();
+ headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
+
+ if (StringUtils.isNoneEmpty(param1)) {
+ cacheEndPoint = cacheEndPoint.replace("param1", param1);
+ }
+ if (StringUtils.isNoneEmpty(param2)) {
+ cacheEndPoint = cacheEndPoint.replace("param2", param2);
+ }
+ UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(rallyProcessorConfig.getCustomApiBaseUrl());
+ uriBuilder.path("/");
+ uriBuilder.path(cacheEndPoint);
+
+ HttpEntity> entity = new HttpEntity<>(headers);
+
+ RestTemplate restTemplate = new RestTemplate();
+ ResponseEntity response = null;
+ try {
+ response = restTemplate.exchange(uriBuilder.toUriString(), HttpMethod.GET, entity, String.class);
+ } catch (RuntimeException e) {
+ log.error("[RALLY-CUSTOMAPI-CACHE-EVICT]. Error while consuming rest service", e);
+ }
+
+ if (null != response && response.getStatusCode().is2xxSuccessful()) {
+ cleaned = true;
+ log.info("[RALLY-CUSTOMAPI-CACHE-EVICT]. Successfully evicted cache for {} and {} ", param1, param2);
+ } else {
+ log.error("[RALLY-CUSTOMAPI-CACHE-EVICT]. Error while evicting cache for {} and {} ", param1, param2);
+ }
+ return cleaned;
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/FetchProjectConfiguration.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/FetchProjectConfiguration.java
new file mode 100644
index 000000000..da29fdb57
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/FetchProjectConfiguration.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.config;
+
+import com.publicissapient.kpidashboard.rally.model.ProjectConfFieldMapping;
+
+import java.util.List;
+
+
+public interface FetchProjectConfiguration {
+ ProjectConfFieldMapping fetchConfiguration(String projectId);
+
+ List fetchBasicProjConfId(String toolName, boolean queryEnabled, boolean isKanban);
+
+ ProjectConfFieldMapping fetchConfigurationBasedOnSprintId(String sprintId);
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/FetchProjectConfigurationImpl.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/FetchProjectConfigurationImpl.java
new file mode 100644
index 000000000..fe8db1a4e
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/FetchProjectConfigurationImpl.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.config;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import com.publicissapient.kpidashboard.rally.constant.RallyConstants;
+import com.publicissapient.kpidashboard.rally.model.RallyToolConfig;
+import com.publicissapient.kpidashboard.rally.model.ProjectConfFieldMapping;
+import org.apache.commons.collections4.CollectionUtils;
+import org.bson.types.ObjectId;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.publicissapient.kpidashboard.common.constant.ProcessorConstants;
+import com.publicissapient.kpidashboard.common.model.application.FieldMapping;
+import com.publicissapient.kpidashboard.common.model.application.ProjectBasicConfig;
+import com.publicissapient.kpidashboard.common.model.application.ProjectToolConfig;
+import com.publicissapient.kpidashboard.common.model.connection.Connection;
+import com.publicissapient.kpidashboard.common.model.jira.SprintDetails;
+import com.publicissapient.kpidashboard.common.repository.application.FieldMappingRepository;
+import com.publicissapient.kpidashboard.common.repository.application.ProjectBasicConfigRepository;
+import com.publicissapient.kpidashboard.common.repository.application.ProjectToolConfigRepository;
+import com.publicissapient.kpidashboard.common.repository.connection.ConnectionRepository;
+import com.publicissapient.kpidashboard.common.repository.jira.SprintRepository;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Service
+public class FetchProjectConfigurationImpl implements FetchProjectConfiguration {
+
+ @Autowired
+ private FieldMappingRepository fieldMappingRepository;
+
+ @Autowired
+ private ProjectToolConfigRepository toolRepository;
+
+ @Autowired
+ private ProjectBasicConfigRepository projectConfigRepository;
+
+ @Autowired
+ private ConnectionRepository connectionRepository;
+
+ @Autowired
+ private SprintRepository sprintRepository;
+
+ @Override
+ public List fetchBasicProjConfId(String toolName, boolean queryEnabled, boolean isKanban) {
+ List allProjects = projectConfigRepository.findByKanbanAndProjectOnHold(isKanban, false);
+ List projectConfigsIds = allProjects.stream().map(projConf -> projConf.getId())
+ .collect(Collectors.toList());
+ List projectToolConfigs = toolRepository
+ .findByToolNameAndQueryEnabledAndBasicProjectConfigIdIn(toolName, queryEnabled, projectConfigsIds);
+ return projectToolConfigs.stream().map(toolConfig -> toolConfig.getBasicProjectConfigId().toString())
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public ProjectConfFieldMapping fetchConfigurationBasedOnSprintId(String sprintId) {
+ ProjectConfFieldMapping projectConfFieldMapping = null;
+ SprintDetails sprintDetails = sprintRepository.findBySprintID(sprintId);
+ ProjectBasicConfig projectBasicConfig = projectConfigRepository.findById(sprintDetails.getBasicProjectConfigId())
+ .orElse(new ProjectBasicConfig());
+
+ FieldMapping fieldMapping = fieldMappingRepository
+ .findByBasicProjectConfigId(sprintDetails.getBasicProjectConfigId());
+ List projectToolConfigs = toolRepository
+ .findByBasicProjectConfigId(sprintDetails.getBasicProjectConfigId());
+ if (CollectionUtils.isNotEmpty(projectToolConfigs)) {
+ ProjectToolConfig projectToolConfig = projectToolConfigs.get(0);
+ if (null != projectToolConfig.getConnectionId()) {
+ Optional jiraConnOpt = connectionRepository.findById(projectToolConfig.getConnectionId());
+ RallyToolConfig rallyToolConfig = createJiraToolConfig(projectToolConfig, jiraConnOpt);
+ projectConfFieldMapping = createProjectConfFieldMapping(fieldMapping, projectBasicConfig, projectToolConfig,
+ rallyToolConfig);
+ }
+ }
+ return projectConfFieldMapping;
+ }
+
+ @Override
+ public ProjectConfFieldMapping fetchConfiguration(String projectId) {
+ ObjectId projectConfigId = new ObjectId(projectId);
+ ProjectConfFieldMapping projectConfFieldMapping = null;
+ ProjectBasicConfig projectBasicConfig = projectConfigRepository.findById(projectConfigId).orElse(null);
+ FieldMapping fieldMapping = fieldMappingRepository.findByBasicProjectConfigId(projectConfigId);
+ List projectToolConfigs = toolRepository
+ .findByToolNameAndBasicProjectConfigId(RallyConstants.RALLY, projectConfigId);
+ if (CollectionUtils.isNotEmpty(projectToolConfigs)) {
+ ProjectToolConfig projectToolConfig = projectToolConfigs.get(0);
+ if (null != projectToolConfig.getConnectionId()) {
+ Optional jiraConnOpt = connectionRepository.findById(projectToolConfig.getConnectionId());
+ RallyToolConfig rallyToolConfig = createJiraToolConfig(projectToolConfig, jiraConnOpt);
+ projectConfFieldMapping = createProjectConfFieldMapping(fieldMapping, projectBasicConfig, projectToolConfig,
+ rallyToolConfig);
+ }
+ }
+ return projectConfFieldMapping;
+ }
+
+ private RallyToolConfig createJiraToolConfig(ProjectToolConfig projectToolConfig, Optional jiraConnOpt) {
+ RallyToolConfig rallyToolConfig = new RallyToolConfig();
+ // Todo: check the beanUtils func changed to import
+ // org.springframework.beans.BeanUtils;
+ BeanUtils.copyProperties(projectToolConfig, rallyToolConfig);
+
+ if (jiraConnOpt.isPresent()) {
+
+ rallyToolConfig.setConnection(jiraConnOpt);
+ }
+ return rallyToolConfig;
+ }
+
+ private ProjectConfFieldMapping createProjectConfFieldMapping(FieldMapping fieldMapping,
+ ProjectBasicConfig projectConfig, ProjectToolConfig projectToolConfig, RallyToolConfig rallyToolConfig) {
+ ProjectConfFieldMapping projectConfFieldMapping = ProjectConfFieldMapping.builder().build();
+
+ if (projectConfig != null) {
+ projectConfFieldMapping.setProjectBasicConfig(projectConfig);
+ projectConfFieldMapping.setBasicProjectConfigId(projectConfig.getId());
+ projectConfFieldMapping.setKanban(projectConfig.getIsKanban());
+ projectConfFieldMapping.setBasicProjectConfigId(projectConfig.getId());
+ projectConfFieldMapping.setProjectName(projectConfig.getProjectName());
+ }
+
+ if (rallyToolConfig != null) {
+ projectConfFieldMapping.setJira(rallyToolConfig);
+ }
+
+ if (projectToolConfig != null) {
+ projectConfFieldMapping.setProjectToolConfig(projectToolConfig);
+ projectConfFieldMapping.setJiraToolConfigId(projectToolConfig.getId());
+ }
+
+ if (fieldMapping != null) {
+ projectConfFieldMapping.setFieldMapping(fieldMapping);
+ }
+
+ return projectConfFieldMapping;
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/KafkaProducerConfig.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/KafkaProducerConfig.java
new file mode 100644
index 000000000..c7a8c32bd
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/KafkaProducerConfig.java
@@ -0,0 +1,35 @@
+package com.publicissapient.kpidashboard.rally.config;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.kafka.clients.producer.ProducerConfig;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.core.DefaultKafkaProducerFactory;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.kafka.core.ProducerFactory;
+import org.springframework.kafka.support.serializer.JsonSerializer;
+
+@Configuration
+public class KafkaProducerConfig {
+
+ @Value(value = "${spring.kafka.producer.bootstrap-servers}")
+ private String bootstrapAddress;
+
+ @Bean
+ public ProducerFactory producerFactory() {
+ Map configProps = new HashMap<>();
+ configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress);
+ configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+ configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
+ return new DefaultKafkaProducerFactory<>(configProps);
+ }
+
+ @Bean
+ public KafkaTemplate kafkaTemplate() {
+ return new KafkaTemplate<>(producerFactory());
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/MongoDBConfig.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/MongoDBConfig.java
new file mode 100644
index 000000000..3964b6933
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/MongoDBConfig.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoClients;
+
+@Configuration
+@PropertySource({"classpath:application.properties"})
+public class MongoDBConfig {
+
+ @Value("${mongodb.connection.atlas}")
+ private boolean useAtlasDB;
+
+ @Value("${spring.data.mongodb.uri}")
+ private String mongoDBUri;
+
+ @Value("${spring.data.mongodb.atlas.uri}")
+ private String atlasUri;
+
+ public String getMongoDBUri() {
+ return useAtlasDB ? atlasUri : mongoDBUri;
+ }
+
+ @Bean
+ public MongoClient mongoClient() {
+ return MongoClients.create(getMongoDBUri());
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/RallyProcessorConfig.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/RallyProcessorConfig.java
new file mode 100644
index 000000000..87dc61dd9
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/RallyProcessorConfig.java
@@ -0,0 +1,81 @@
+package com.publicissapient.kpidashboard.rally.config;
+
+import java.util.List;
+import java.util.Map;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+import lombok.Data;
+
+@Component
+@ConfigurationProperties(prefix = "rally")
+@Data
+public class RallyProcessorConfig {
+ private String cron;
+ private String username;
+ private String password;
+ private String apiEndpoint;
+ private int pageSize = 100;
+ private int maxRetries = 3;
+ private long retryDelay = 5000;
+ private String[] workspaceIds;
+ private String[] projectIds;
+ private String[] storyTypes = {"HierarchicalRequirement", "Defect", "Task", "TestCase", "DefectSuite", "Feature"};
+ private String[] statusTypes = {"Defined", "In-Progress", "Completed", "Accepted", "Backlog", "Ready", "InDevelopment", "Testing", "Done"};
+ private String[] workflowStates = {"Development", "QA", "Delivered", "DOR", "DOD"};
+
+ private String customApiBaseUrl;
+ private Integer socketTimeOut;
+ private int threadPoolSize;
+ private Integer prevMonthCountToFetchData = 3;
+ private Integer daysToReduce;
+ private Integer chunkSize;
+ private String uiHost;
+ private String rallyApiBaseUrl;
+ private String rallyApiKey;
+ private boolean fetchMetadata;
+ private long subsequentApiCallDelayInMilli;
+ private List rcaValuesForCodeIssue;
+ private List excludeLinks;
+ private String jiraCloudGetUserApi;
+ private String jiraServerGetUserApi;
+ private String jiraCloudSprintReportApi;
+ private String jiraServerSprintReportApi;
+ private String jiraDirectTicketLinkKey;
+ private String jiraCloudDirectTicketLinkKey;
+ private String jiraSprintByBoardUrlApi;
+ private String jiraEpicApi;
+ private Integer sprintReportCountToBeFetched;
+ private boolean considerStartDate;
+ private Map notificationSubject;
+ private Map mailTemplate;
+ private String samlTokenStartString;
+ private String samlTokenEndString;
+ private String samlUrlStartString;
+ private String samlUrlEndString;
+ private String jiraVersionApi;
+ private String jiraCloudVersionApi;
+ private String jiraServerVersionReportApi;
+ private String jiraCloudVersionReportApi;
+ private List domainNames;
+
+ @Value("${aesEncryptionKey}")
+ private String aesEncryptionKey;
+
+ @Value("${notification.switch}")
+ private boolean notificationSwitch;
+
+ @Value("${flag.mailWithoutKafka}")
+ private boolean mailWithoutKafka;
+
+ @Value("${kafka.mailtopic}")
+ private String kafkaMailTopic;
+
+ public List getDomainNames() {
+ return domainNames;
+ }
+
+ public void setDomainNames(List domainNames) {
+ this.domainNames = domainNames;
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/WebSecurityConfig.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/WebSecurityConfig.java
new file mode 100644
index 000000000..c415479ef
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/config/WebSecurityConfig.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.publicissapient.kpidashboard.rally.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
+
+/**
+ * Security configuration
+ *
+ * @author anisingh4
+ */
+@Configuration
+public class WebSecurityConfig {
+
+ @Bean
+ public WebSecurityCustomizer webSecurityCustomizer() {
+ return web -> web.ignoring().requestMatchers("/api/job/*", "/togglz-console/*");
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/constant/RallyConstants.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/constant/RallyConstants.java
new file mode 100644
index 000000000..57bf5dca3
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/constant/RallyConstants.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.constant;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.springframework.stereotype.Service;
+
+@Service
+public final class RallyConstants {
+
+ public static final Set ISSUE_FIELD_SET = new HashSet<>(); // NOSONAR
+ public static final String STATUS = "status";
+ public static final String ASSIGNEE = "assignee";
+ public static final String PRIORITY = "priority";
+ public static final String FIXVERSION = "fix version";
+ public static final String DUEDATE = "duedate";
+ public static final String LABELS = "Labels";
+ public static final String CUSTOM_FIELD = "CustomField";
+ public static final String ISSUE_TYPE = "IssueType";
+ public static final String RCA_CAUSE_NONE = "None";
+ public static final String RCA_NOT_AVAILABLE = "RCA Not Available";
+ public static final String ISSUE_TYPE_DEFECT = "Defect";
+ public static final String TEST_AUTOMATED = "Automated";
+ public static final String YES = "Yes";
+ public static final String VALUE = "value";
+ public static final String CODE_ISSUE = "code issue";
+ public static final String ACTUAL_ESTIMATION = "Actual Estimation";
+ public static final String BUFFERED_ESTIMATION = "Buffered Estimation";
+ public static final String STORY_POINT = "Story Point";
+ public static final String JIRA_ISSUE_CHANGE_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSS";
+ public static final String EMPTY_STR = "";
+ public static final String FALSE = "False";
+ public static final String START_AT_ATTRIBUTE = "startAt";
+ public static final String MAX_RESULTS_ATTRIBUTE = "maxResults";
+ public static final int MAX_JQL_LENGTH_FOR_HTTP_GET = 3000;
+ public static final String JQL_ATTRIBUTE = "jql";
+ public static final String FILTER_FAVOURITE_PATH = "filter/favourite";
+ public static final String FILTER_PATH_FORMAT = "filter/%s";
+ public static final String SEARCH_URI_PREFIX = "search";
+ public static final String EXPAND_ATTRIBUTE = "expand";
+ public static final String FIELDS_ATTRIBUTE = "fields";
+ public static final String DATE_TIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
+ public static final String AGGREGATED_TIME_SPENT = "aggregatetimespent";
+ public static final String AGGREGATED_TIME_ORIGINAL = "aggregatetimeoriginalestimate";
+ public static final String AGGREGATED_TIME_REMAIN = "aggregatetimeestimate";
+ public static final String ID = "id";
+ public static final String COMPONENT = "Component";
+ public static final String RALLY = "Rally";
+ public static final String TOOL_RALLY = "RALLY";
+ public static final String ORDERBY = "order by";
+
+ public static final String PARENT = "parent";
+ public static final String KEY = "key";
+ public static final String USER = "User";
+ public static final String SPACE = " ";
+ public static final String EPIC = "Epic";
+ public static final String WORKLOG = "timespent";
+ public static final String FLAG_STATUS_FOR_SERVER = "Flag as Impediment";
+ public static final String FLAG_STATUS_FOR_CLOUD = "Flagged";
+ public static final String QUERYDATEFORMAT = "yyyy-MM-dd HH:mm";
+ public static final String TO_DO = "To Do";
+ public static final String DONE = "Done";
+ public static final String ERROR_MSG_401 = "Error 401 connecting to RALLY server, your credentials are probably wrong. Note: Ensure you are using RALLY user name not your email address.";
+ public static final String ERROR_MSG_NO_RESULT_WAS_AVAILABLE = "No result was available from Jira unexpectedly - defaulting to blank response. The reason for this fault is the following : {}";
+ public static final String TOTAL_ISSUES = "total issues";
+ public static final String PROCESSED_ISSUES = "processed issues";
+ public static final String PAGE_START = "pageStart";
+ public static final String BOARD_ID = "boardId";
+ public static final String NAME = "name";
+ public static final String EPIC_RESOLUTION_DATE = "resolutiondate";
+ public static final String ERROR_NOTIFICATION_SUBJECT_KEY = "errorInJiraProcessor";
+ public static final String OUTLIER_NOTIFICATION_SUBJECT_KEY = "outlierInJiraProcessor";
+ public static final String ERROR_MAIL_TEMPLATE_KEY = "Error_In_Jira_Processor";
+ public static final String OUTLIER_MAIL_TEMPLATE_KEY = "Outlier_In_Jira_Processor";
+
+ public static final String WORKSPACE_PATH = "/workspace";
+ public static final String HIERARCHICAL_REQUIREMENT_PATH = "/hierarchicalrequirement";
+ public static final String DEFECT_PATH = "/defect";
+ public static final String ITERATION_PATH = "/iteration";
+ public static final String RELEASE_PATH = "/release";
+ public static final String STATE_PATH = "/state";
+ public static final String TYPE_DEFINITION_PATH = "/typedefinition";
+ public static final String ALLOWED_VALUES_PATH = "/allowedValues";
+
+ public static final String API_VERSION = "v2.0";
+ public static final String ZSESSIONID = "ZSESSIONID";
+ public static final String SPRINT_ID = "_refObjectUUID";
+ public static final String QUERY_PARAM = "query";
+ public static final String FETCH_PARAM = "fetch";
+ public static final String START_PARAM = "start";
+ public static final String PAGESIZE_PARAM = "pagesize";
+ public static final String PROJECT_PARAM = "Project.Name";
+ public static final String ATTRIBUTE_NAME_PARAM = "attributeName";
+
+ public static final int DEFAULT_PAGE_SIZE = 100;
+ public static final int DEFAULT_START_INDEX = 1;
+
+ static {
+ ISSUE_FIELD_SET.add("*all,-attachment,-worklog,-comment,-votes,-watches");
+ }
+
+ private RallyConstants() {
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/controller/JobController.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/controller/JobController.java
new file mode 100644
index 000000000..3332841f0
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/controller/JobController.java
@@ -0,0 +1,292 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+package com.publicissapient.kpidashboard.rally.controller;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import com.publicissapient.kpidashboard.rally.config.FetchProjectConfiguration;
+import com.publicissapient.kpidashboard.rally.constant.RallyConstants;
+import com.publicissapient.kpidashboard.rally.repository.RallyProcessorRepository;
+import com.publicissapient.kpidashboard.rally.service.OngoingExecutionsService;
+import org.apache.commons.collections4.CollectionUtils;
+import org.bson.types.ObjectId;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.JobParameters;
+import org.springframework.batch.core.JobParametersBuilder;
+import org.springframework.batch.core.JobParametersInvalidException;
+import org.springframework.batch.core.launch.JobLauncher;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
+import org.springframework.batch.core.repository.JobRestartException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.publicissapient.kpidashboard.common.constant.ProcessorConstants;
+import com.publicissapient.kpidashboard.common.model.ProcessorExecutionBasicConfig;
+import com.publicissapient.kpidashboard.common.model.application.ProjectBasicConfig;
+import com.publicissapient.kpidashboard.common.model.application.ProjectToolConfig;
+import com.publicissapient.kpidashboard.common.repository.application.ProjectBasicConfigRepository;
+import com.publicissapient.kpidashboard.common.repository.application.ProjectToolConfigRepository;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author pankumar8
+ */
+@RestController
+@RequestMapping("/api/job")
+@Slf4j
+public class JobController {
+
+ private static final String NUMBER_OF_PROCESSOR_AVAILABLE_MSG = "Total number of processor available : {} = number or projects run in parallel";
+ private static final String PROJECT_ID = "projectId";
+ private static final String SPRINT_ID = "sprintId";
+ private static final String CURRENTTIME = "currentTime";
+ private static final String IS_SCHEDULER = "isScheduler";
+ private static final String VALUE = "false";
+ private static final String PROCESSOR_ID = "processorId";
+ @Autowired
+ JobLauncher jobLauncher;
+
+ @Qualifier("fetchIssueScrumRqlJob")
+ @Autowired
+ Job fetchIssueScrumRqlJob;
+
+ @Qualifier("fetchIssueSprintJob")
+ @Autowired
+ Job fetchIssueSprintJob;
+
+ @Qualifier("runMetaDataStep")
+ @Autowired
+ Job runMetaDataStep;
+
+ @Autowired
+ private ProjectToolConfigRepository toolRepository;
+
+ @Autowired
+ private ProjectBasicConfigRepository projectConfigRepository;
+
+ @Autowired
+ private FetchProjectConfiguration fetchProjectConfiguration;
+
+ @Autowired
+ private OngoingExecutionsService ongoingExecutionsService;
+
+ @Autowired
+ private RallyProcessorRepository rallyProcessorRepository;
+
+ /**
+ * This method is used to start job for the Scrum projects with JQL setup
+ *
+ * @return ResponseEntity
+ */
+ @GetMapping("/startscrumjqljob")
+ public ResponseEntity startScrumJqlJob() {
+ log.info("Request come for job for Scrum project configured with JQL via controller");
+
+ List scrumBoardbasicProjConfIds = fetchProjectConfiguration.fetchBasicProjConfId(RallyConstants.RALLY,
+ true, false);
+
+ List parameterSets = getDynamicParameterSets(scrumBoardbasicProjConfIds);
+ log.info(NUMBER_OF_PROCESSOR_AVAILABLE_MSG, Runtime.getRuntime().availableProcessors());
+
+ ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
+
+ for (JobParameters params : parameterSets) {
+ executorService.submit(() -> {
+ try {
+ jobLauncher.run(fetchIssueScrumRqlJob, params);
+ } catch (Exception e) {
+ log.info("Jira Scrum data for JQL fetch failed for BasicProjectConfigId : {}, with exception : {}",
+ params.getString(PROJECT_ID), e);
+ }
+ });
+ }
+ executorService.shutdown();
+ return ResponseEntity.ok().body("job started for scrum JQL");
+ }
+
+ private List getDynamicParameterSets(List scrumBoardbasicProjConfIds) {
+ return getJobParameters(scrumBoardbasicProjConfIds, rallyProcessorRepository, PROJECT_ID, CURRENTTIME,
+ IS_SCHEDULER, VALUE, PROCESSOR_ID);
+ }
+
+ public static List getJobParameters(List scrumBoardbasicProjConfIds,
+ RallyProcessorRepository rallyProcessorRepository, String projectId, String currenttime, String isScheduler,
+ String value, String processorId) {
+ List parameterSets = new ArrayList<>();
+ ObjectId jiraProcessorId = rallyProcessorRepository.findByProcessorName(ProcessorConstants.JIRA).getId();
+ scrumBoardbasicProjConfIds.forEach(configId -> {
+ JobParametersBuilder jobParametersBuilder = new JobParametersBuilder();
+ // Add dynamic parameters as needed
+ jobParametersBuilder.addString(projectId, configId);
+ jobParametersBuilder.addLong(currenttime, System.currentTimeMillis());
+ jobParametersBuilder.addString(isScheduler, value);
+ jobParametersBuilder.addString(processorId, jiraProcessorId.toString());
+
+ JobParameters params = jobParametersBuilder.toJobParameters();
+ parameterSets.add(params);
+ });
+
+ return parameterSets;
+ }
+
+ /**
+ * This method is used to fetch the sprint report data
+ *
+ * @param sprintId
+ * sprintId
+ * @return ResponseEntity
+ */
+ @PostMapping(value = "/startfetchsprintjob", consumes = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity startFetchSprintJob(@RequestBody String sprintId) {
+ log.info("Request coming for fetching sprint job");
+ ObjectId jiraProcessorId = rallyProcessorRepository.findByProcessorName(ProcessorConstants.JIRA).getId();
+ CompletableFuture.runAsync(() -> {
+ JobParametersBuilder jobParametersBuilder = new JobParametersBuilder();
+ jobParametersBuilder.addString(SPRINT_ID, sprintId);
+ jobParametersBuilder.addLong(CURRENTTIME, System.currentTimeMillis());
+ jobParametersBuilder.addString(PROCESSOR_ID, jiraProcessorId.toString());
+ JobParameters params = jobParametersBuilder.toJobParameters();
+ try {
+ jobLauncher.run(fetchIssueSprintJob, params);
+ } catch (Exception e) {
+ log.info("Jira Sprint data fetch failed for SprintId : {}, with exception : {}",
+ params.getString(SPRINT_ID), e);
+ }
+ });
+ return ResponseEntity.ok().body("job started for Sprint : " + sprintId);
+ }
+
+ /**
+ * This method is used to fetch the jira issues based on project id
+ *
+ * @param processorExecutionBasicConfig
+ * processorExecutionBasicConfig
+ * @return ResponseEntity
+ */
+ @PostMapping("/startprojectwiseissuejob")
+ public ResponseEntity startProjectWiseIssueJob(
+ @RequestBody ProcessorExecutionBasicConfig processorExecutionBasicConfig) {
+ log.info("Request coming for fetching issue job");
+
+ String basicProjectConfigId = processorExecutionBasicConfig.getProjectBasicConfigIds().get(0);
+ if (ongoingExecutionsService.isExecutionInProgress(basicProjectConfigId)) {
+ log.error("An execution is already in progress");
+ return ResponseEntity.badRequest()
+ .body("Jira processor run is already in progress for this project. Please try after some time.");
+ }
+
+ // Mark the execution as in progress before starting the job asynchronously
+ ongoingExecutionsService.markExecutionInProgress(basicProjectConfigId);
+ ObjectId jiraProcessorId = rallyProcessorRepository.findByProcessorName(RallyConstants.RALLY).getId();
+ // Start the job asynchronously
+ CompletableFuture.runAsync(() -> {
+ JobParametersBuilder jobParametersBuilder = new JobParametersBuilder();
+ jobParametersBuilder.addString(PROJECT_ID, basicProjectConfigId);
+ jobParametersBuilder.addLong(CURRENTTIME, System.currentTimeMillis());
+ jobParametersBuilder.addString(IS_SCHEDULER, VALUE);
+ jobParametersBuilder.addString(PROCESSOR_ID, jiraProcessorId.toString());
+ JobParameters params = jobParametersBuilder.toJobParameters();
+
+ try {
+ Optional projBasicConfOpt = projectConfigRepository
+ .findById(new ObjectId(basicProjectConfigId));
+
+ runProjectBasedOnConfig(basicProjectConfigId, params, projBasicConfOpt);
+ } catch (Exception e) {
+ log.error("Jira fetch failed for BasicProjectConfigId : {}, with exception : {}",
+ params.getString(PROJECT_ID), e);
+ }
+ });
+ return ResponseEntity.ok().body("Job started for BasicProjectConfigId: " + basicProjectConfigId);
+ }
+
+ /**
+ * This method is used to fetch the metadata
+ *
+ * @param projectBasicConfigId
+ * projectBasicConfigId
+ * @return ResponseEntity
+ */
+ @PostMapping(value = "/runMetadataStep", consumes = MediaType.APPLICATION_JSON_VALUE)
+ public ResponseEntity runMetadataStep(@RequestBody String projectBasicConfigId) {
+ log.info("Request coming for fetching sprint job");
+ ObjectId jiraProcessorId = rallyProcessorRepository.findByProcessorName(ProcessorConstants.JIRA).getId();
+ CompletableFuture.runAsync(() -> {
+ JobParametersBuilder jobParametersBuilder = new JobParametersBuilder();
+ jobParametersBuilder.addString(PROJECT_ID, projectBasicConfigId);
+ jobParametersBuilder.addLong(CURRENTTIME, System.currentTimeMillis());
+ jobParametersBuilder.addString(PROCESSOR_ID, jiraProcessorId.toString());
+ jobParametersBuilder.addString(IS_SCHEDULER, VALUE);
+ JobParameters params = jobParametersBuilder.toJobParameters();
+ try {
+ jobLauncher.run(runMetaDataStep, params);
+ } catch (Exception e) {
+ log.info("Jira Metadata failed for ProjectBasicConfigId : {}, with exception : {}",
+ params.getString(PROJECT_ID), e);
+ }
+ });
+ return ResponseEntity.ok().body("job started for Project : " + projectBasicConfigId);
+ }
+
+ private void runProjectBasedOnConfig(String basicProjectConfigId, JobParameters params,
+ Optional projBasicConfOpt) throws JobExecutionAlreadyRunningException,
+ JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException {
+ if (projBasicConfOpt.isPresent()) {
+ ProjectBasicConfig projectBasicConfig = projBasicConfOpt.get();
+ List projectToolConfigs = toolRepository
+ .findByToolNameAndBasicProjectConfigId(RallyConstants.RALLY, projectBasicConfig.getId());
+
+ if (!projectBasicConfig.isKanban()) {
+ // Project is scrum
+ launchJobBasedOnQueryEnabledForScrum(basicProjectConfigId, params, projectToolConfigs);
+ }
+ }
+ }
+
+ private void launchJobBasedOnQueryEnabledForScrum(String basicProjectConfigId, JobParameters params,
+ List projectToolConfigs) throws JobExecutionAlreadyRunningException, JobRestartException,
+ JobInstanceAlreadyCompleteException, JobParametersInvalidException {
+ if (CollectionUtils.isNotEmpty(projectToolConfigs)) {
+ ProjectToolConfig projectToolConfig = projectToolConfigs.get(0);
+
+ if (projectToolConfig.isQueryEnabled()) {
+ // JQL is setup for the project
+ jobLauncher.run(fetchIssueScrumRqlJob, params);
+ }
+ } else {
+ log.info("removing project with basicProjectConfigId {}", basicProjectConfigId);
+ // Mark the execution as completed
+ ongoingExecutionsService.markExecutionAsCompleted(basicProjectConfigId);
+ }
+ }
+
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/helper/AdditionalFilterHelper.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/helper/AdditionalFilterHelper.java
new file mode 100644
index 000000000..95c1e9b2d
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/helper/AdditionalFilterHelper.java
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.helper;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.publicissapient.kpidashboard.rally.constant.RallyConstants;
+import com.publicissapient.kpidashboard.rally.model.ProjectConfFieldMapping;
+import com.publicissapient.kpidashboard.rally.util.JiraIssueClientUtil;
+import com.publicissapient.kpidashboard.rally.util.JiraProcessorUtil;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.ListUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.codehaus.jettison.json.JSONArray;
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.atlassian.jira.rest.client.api.domain.BasicComponent;
+import com.atlassian.jira.rest.client.api.domain.Issue;
+import com.atlassian.jira.rest.client.api.domain.IssueField;
+import com.publicissapient.kpidashboard.common.constant.CommonConstant;
+import com.publicissapient.kpidashboard.common.model.application.AdditionalFilter;
+import com.publicissapient.kpidashboard.common.model.application.AdditionalFilterCategory;
+import com.publicissapient.kpidashboard.common.model.application.AdditionalFilterConfig;
+import com.publicissapient.kpidashboard.common.model.application.AdditionalFilterValue;
+import com.publicissapient.kpidashboard.common.model.application.FieldMapping;
+import com.publicissapient.kpidashboard.common.service.AdditionalFilterCategoryService;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Component
+@Slf4j
+public class AdditionalFilterHelper {
+
+ @Autowired
+ private AdditionalFilterCategoryService additionalFilterCategoryService;
+
+ public List getAdditionalFilter(Issue issue, ProjectConfFieldMapping projectConfig) {
+ List additionalFilters = new ArrayList<>();
+ if (issue != null && projectConfig != null) {
+ String basicProjectConfigId = projectConfig.getBasicProjectConfigId().toHexString();
+
+ FieldMapping fieldMapping = projectConfig.getFieldMapping();
+
+ List additionalFilterConfigs = ListUtils
+ .emptyIfNull(fieldMapping.getAdditionalFilterConfig());
+
+ List additionalFilterCategories = additionalFilterCategoryService
+ .getAdditionalFilterCategories();
+ Map additionalFilterCategoryMap = additionalFilterCategories.stream()
+ .collect(Collectors.toMap(AdditionalFilterCategory::getFilterCategoryId, afc -> afc));
+
+ for (AdditionalFilterConfig additionalFilterConfig : additionalFilterConfigs) {
+ if (additionalFilterCategoryMap.get(additionalFilterConfig.getFilterId()) != null) {
+ AdditionalFilter additionalFilter = new AdditionalFilter();
+ additionalFilter.setFilterId(additionalFilterConfig.getFilterId());
+ List additionalFilterValues = getAdditionalFilterValues(issue, additionalFilterConfig,
+ basicProjectConfigId);
+ additionalFilter.setFilterValues(additionalFilterValues);
+ if (CollectionUtils.isNotEmpty(additionalFilterValues)) {
+ additionalFilters.add(additionalFilter);
+ }
+ }
+ }
+ }
+
+ return additionalFilters;
+ }
+
+ private String createAdditionalFilterValueId(String value, String filterId, String basicProjectConfigId) {
+ return value + CommonConstant.ADDITIONAL_FILTER_VALUE_ID_SEPARATOR + filterId +
+ CommonConstant.ADDITIONAL_FILTER_VALUE_ID_SEPARATOR + basicProjectConfigId;
+ }
+
+ private List getAdditionalFilterValues(Issue issue,
+ AdditionalFilterConfig additionalFilterConfig, String basicProjectConfigId) {
+
+ List values = new ArrayList<>();
+
+ if (CommonConstant.LABELS.equals(additionalFilterConfig.getIdentifyFrom()) &&
+ CollectionUtils.isNotEmpty(issue.getLabels())) {
+ Set labels = getLabels(issue, additionalFilterConfig);
+ labels.forEach(label -> {
+ AdditionalFilterValue additionalFilterValue = new AdditionalFilterValue();
+ additionalFilterValue.setValue(label);
+ additionalFilterValue.setValueId(
+ createAdditionalFilterValueId(label, additionalFilterConfig.getFilterId(), basicProjectConfigId));
+ values.add(additionalFilterValue);
+ });
+
+ } else if (CommonConstant.COMPONENT.equals(additionalFilterConfig.getIdentifyFrom())) {
+ Set components = getComponents(issue, additionalFilterConfig);
+ components.forEach(component -> {
+ AdditionalFilterValue additionalFilterValue = new AdditionalFilterValue();
+ additionalFilterValue.setValue(component.getName());
+ additionalFilterValue.setValueId(createAdditionalFilterValueId(component.getName(),
+ additionalFilterConfig.getFilterId(), basicProjectConfigId));
+ values.add(additionalFilterValue);
+ });
+ } else if (CommonConstant.CUSTOM_FIELD.equals(additionalFilterConfig.getIdentifyFrom())) {
+
+ Set customFieldValues = getCustomFieldValues(issue, additionalFilterConfig);
+
+ customFieldValues.forEach(customFieldValue -> {
+ AdditionalFilterValue additionalFilterValue = new AdditionalFilterValue();
+ additionalFilterValue.setValue(customFieldValue);
+ additionalFilterValue.setValueId(createAdditionalFilterValueId(customFieldValue,
+ additionalFilterConfig.getFilterId(), basicProjectConfigId));
+ values.add(additionalFilterValue);
+ });
+ }
+
+ return values;
+ }
+
+ private Set getLabels(Issue issue, AdditionalFilterConfig additionalFilterConfig) {
+ Set configuredLabels = additionalFilterConfig.getValues();
+ Set labels = issue.getLabels();
+ Set common = new HashSet<>(labels);
+ common.retainAll(configuredLabels);
+ return common;
+ }
+
+ private Set getComponents(Issue issue, AdditionalFilterConfig additionalFilterConfig) {
+ Set configuredComponentNames = additionalFilterConfig.getValues();
+ Iterable components = issue.getComponents();
+ List componentList = new ArrayList<>();
+ components.forEach(componentList::add);
+
+ Set common = new HashSet<>();
+
+ for (BasicComponent basicComponent : componentList) {
+ if (CollectionUtils.isNotEmpty(configuredComponentNames) &&
+ configuredComponentNames.contains(basicComponent.getName())) {
+ common.add(basicComponent);
+ }
+ }
+
+ return common;
+ }
+
+ private Set getCustomFieldValues(Issue issue, AdditionalFilterConfig additionalFilterConfig) {
+ Map fields = JiraIssueClientUtil.buildFieldMap(issue.getFields());
+ Set values = new HashSet<>();
+ String customField = additionalFilterConfig.getIdentificationField();
+
+ if (null != fields.get(customField) &&
+ StringUtils.isNotEmpty(JiraProcessorUtil.deodeUTF8String(fields.get(customField).getValue()))) {
+ try {
+ if (fields.get(customField).getValue() instanceof JSONObject) {
+ JSONObject jsonObject = (JSONObject) fields.get(customField).getValue();
+ getValueFromFieldJsonObject(values, jsonObject);
+ } else if (fields.get(customField).getValue() instanceof JSONArray) {
+ JSONArray fieldArray = (JSONArray) fields.get(customField).getValue();
+ if (fieldArray.length() > 0) {
+ for (int i = 0; i < fieldArray.length(); i++) {
+ getValueFromFieldJsonObject(values, (JSONObject) fieldArray.get(i));
+ }
+ }
+ } else {
+ values.add(JiraProcessorUtil.deodeUTF8String(fields.get(customField).getValue()));
+ }
+ } catch (JSONException e) {
+ log.error("Error while parsing custom field " + customField, e);
+ }
+ }
+ return values;
+ }
+
+ private void getValueFromFieldJsonObject(Set values, JSONObject jsonObject) {
+ if (jsonObject != null) {
+ String value = jsonObject.optString(RallyConstants.VALUE, null);
+ if (StringUtils.isNotBlank(value)) {
+ values.add(value);
+ } else {
+ String name = jsonObject.optString(RallyConstants.NAME, null);
+ if (StringUtils.isNotBlank(name)) {
+ values.add(name);
+ }
+ }
+ }
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/helper/BuilderFactory.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/helper/BuilderFactory.java
new file mode 100644
index 000000000..38609038a
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/helper/BuilderFactory.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.helper;
+
+import org.springframework.batch.core.job.builder.JobBuilder;
+import org.springframework.batch.core.repository.JobRepository;
+import org.springframework.batch.core.step.builder.StepBuilder;
+import org.springframework.stereotype.Component;
+
+@Component
+public class BuilderFactory {
+
+ public JobBuilder getJobBuilder(String name, JobRepository jobRepository) {
+ return new JobBuilder(name, jobRepository);
+ }
+
+ public StepBuilder getStepBuilder(String name, JobRepository jobRepository) {
+ return new StepBuilder(name, jobRepository);
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/helper/RallyHelper.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/helper/RallyHelper.java
new file mode 100644
index 000000000..b97885148
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/helper/RallyHelper.java
@@ -0,0 +1,190 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.helper;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+import org.joda.time.DateTime;
+import org.json.simple.JSONArray;
+import org.springframework.stereotype.Component;
+
+import com.atlassian.jira.rest.client.api.RestClientException;
+import com.atlassian.jira.rest.client.api.domain.ChangelogGroup;
+import com.atlassian.jira.rest.client.api.domain.Issue;
+import com.atlassian.jira.rest.client.api.domain.IssueField;
+import com.atlassian.jira.rest.client.api.domain.User;
+import com.atlassian.jira.rest.client.api.domain.Version;
+import com.google.common.collect.Lists;
+import com.publicissapient.kpidashboard.common.model.jira.SprintDetails;
+import com.publicissapient.kpidashboard.rally.constant.RallyConstants;
+import com.publicissapient.kpidashboard.rally.model.HierarchicalRequirement;
+import com.publicissapient.kpidashboard.rally.model.RallyResponse;
+import com.publicissapient.kpidashboard.rally.util.JiraProcessorUtil;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+public class RallyHelper {
+
+ public static final Comparator SPRINT_COMPARATOR = (SprintDetails o1, SprintDetails o2) -> {
+ int cmp1 = ObjectUtils.compare(o1.getStartDate(), o2.getStartDate());
+ if (cmp1 != 0) {
+ return cmp1;
+ }
+ return ObjectUtils.compare(o1.getEndDate(), o2.getEndDate());
+ };
+ private static final String ERROR_MSG_401 = "Error 401 connecting to RALLY server, your credentials are probably wrong. Note: Ensure you are using RALLY user name not your email address.";
+ private static final String ERROR_MSG_NO_RESULT_WAS_AVAILABLE = "No result was available from Jira unexpectedly - defaulting to blank response. The reason for this fault is the following : {}";
+ private static final String MSG_JIRA_CLIENT_SETUP_FAILED = "Jira client setup failed. No results obtained. Check your jira setup.";
+
+ public static Map buildFieldMap(Iterable fields) {
+ Map rt = new HashMap<>();
+
+ if (fields != null) {
+ for (IssueField issueField : fields) {
+ rt.put(issueField.getId(), issueField);
+ }
+ }
+
+ return rt;
+ }
+
+ public static List getLabelsList(Issue issue) {
+ List labels = new ArrayList<>();
+ if (issue.getLabels() != null) {
+ for (String labelName : issue.getLabels()) {
+ labels.add(JiraProcessorUtil.deodeUTF8String(labelName));
+ }
+ }
+ return labels;
+ }
+
+ public static List getAffectedVersions(Issue issue) {
+ List affectedVersions = new ArrayList<>();
+ if (issue.getAffectedVersions() != null) {
+ for (Version affectedVersionName : issue.getAffectedVersions()) {
+ affectedVersions.add(affectedVersionName.getName());
+ }
+ }
+ return affectedVersions;
+ }
+
+ public static String getFieldValue(String customFieldId, Map fields) {
+ Object fieldValue = fields.get(customFieldId).getValue();
+ try {
+ if (fieldValue instanceof Double) {
+ return fieldValue.toString();
+ } else if (fieldValue instanceof JSONObject) {
+ return ((JSONObject) fieldValue).getString(RallyConstants.VALUE);
+ } else if (fieldValue instanceof String) {
+ return fieldValue.toString();
+ }
+ } catch (JSONException e) {
+ log.error("RALLY Processor | Error while parsing RCA Custom_Field", e);
+ }
+ return fieldValue.toString();
+ }
+
+ public static List sortChangeLogGroup(Issue issue) {
+ Iterable changelogItr = issue.getChangelog();
+ List changeLogList = new ArrayList<>();
+ if (null != changelogItr) {
+ changeLogList = Lists.newArrayList(changelogItr.iterator());
+ changeLogList.sort((ChangelogGroup obj1, ChangelogGroup obj2) -> {
+ DateTime activityDate1 = obj1.getCreated();
+ DateTime activityDate2 = obj2.getCreated();
+ return activityDate1.compareTo(activityDate2);
+ });
+ }
+ return changeLogList;
+ }
+
+ public static List getIssuesFromResult(RallyResponse rallyResponse) {
+ if (rallyResponse != null) {
+ return Lists.newArrayList(rallyResponse.getQueryResult().getResults());
+ }
+ return new ArrayList<>();
+ }
+
+ public static String hash(String input) {
+ return String.valueOf(Objects.hash(input));
+ }
+
+ public static String getAssignee(User user) {
+ String userId = "";
+ String query = user.getSelf().getQuery();
+ if (StringUtils.isNotEmpty(query) && (query.contains("accountId") || query.contains("username"))) {
+ userId = query.split("=")[1];
+ }
+ return userId;
+ }
+
+ public static Collection getListFromJson(IssueField issueField) {
+
+ Object value = issueField.getValue();
+ final List list = new ArrayList<>();
+ if (value instanceof JSONArray) {
+
+ ((JSONArray) value).forEach(v -> {
+ try {
+ list.add(((JSONObject) v).get(RallyConstants.VALUE));
+ } catch (JSONException e) {
+ log.error("RALLY PROCESSOR | Error while parsing Atlassian Issue JSON Object", e);
+ }
+ });
+ } else if (value instanceof JSONObject) {
+ try {
+ list.add(((JSONObject) value).get(RallyConstants.VALUE));
+ } catch (JSONException e) {
+ log.error("RALLY PROCESSOR | Error while parsing Atlassian Issue JSON Object", e);
+ }
+ }
+ return list;
+ }
+
+ public static void exceptionBlockProcess(RestClientException e) {
+ if (e.getStatusCode().isPresent() && e.getStatusCode().get() == 401) {
+ log.error(ERROR_MSG_401);
+ } else {
+ log.error(ERROR_MSG_NO_RESULT_WAS_AVAILABLE, e.getCause());
+ }
+ }
+
+ public static String convertDateToCustomFormat(long currentTimeMillis) {
+ Date inputDate = new Date(currentTimeMillis);
+ SimpleDateFormat outputFormat = new SimpleDateFormat("MMMM dd, yyyy, EEEE, hh:mm:ss a");
+
+ String outputStr = outputFormat.format(inputDate);
+
+ return outputStr;
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/helper/ReaderRetryHelper.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/helper/ReaderRetryHelper.java
new file mode 100644
index 000000000..3bfd0ddfe
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/helper/ReaderRetryHelper.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+package com.publicissapient.kpidashboard.rally.helper;
+
+import org.springframework.retry.annotation.Retryable;
+import org.springframework.retry.backoff.FixedBackOffPolicy;
+import org.springframework.retry.policy.SimpleRetryPolicy;
+import org.springframework.retry.support.RetryTemplate;
+
+public class ReaderRetryHelper {
+
+ public static final int MAX_RETRY_ATTEMPT = 3;
+ public static final long TIME_INTERVAL_BETWEEN_RETRY = 5000;
+
+ @Retryable
+ public T executeWithRetry(RetryableOperation operation) throws Exception {
+ RetryTemplate retryTemplate = new RetryTemplate(); // Creating a new RetryTemplate for each retry
+
+ // Configure the retry policy (maximum of 3 retry attempts)
+ SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
+ retryPolicy.setMaxAttempts(MAX_RETRY_ATTEMPT);
+ retryTemplate.setRetryPolicy(retryPolicy);
+
+ // Configure the backoff policy (fixed delay of 3000 milliseconds between
+ // retries)
+ FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
+ backOffPolicy.setBackOffPeriod(TIME_INTERVAL_BETWEEN_RETRY);
+ retryTemplate.setBackOffPolicy(backOffPolicy);
+ return retryTemplate.execute(context -> operation.execute());
+ }
+
+ @FunctionalInterface
+ public interface RetryableOperation {
+ T execute() throws Exception;
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/jobs/RallyProcessorJob.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/jobs/RallyProcessorJob.java
new file mode 100644
index 000000000..40a028ae0
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/jobs/RallyProcessorJob.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+package com.publicissapient.kpidashboard.rally.jobs;
+
+import com.publicissapient.kpidashboard.rally.aspect.TrackExecutionTime;
+import com.publicissapient.kpidashboard.rally.config.RallyProcessorConfig;
+import com.publicissapient.kpidashboard.rally.helper.BuilderFactory;
+import com.publicissapient.kpidashboard.rally.listener.*;
+import com.publicissapient.kpidashboard.rally.model.CompositeResult;
+import com.publicissapient.kpidashboard.rally.model.ReadData;
+import com.publicissapient.kpidashboard.rally.processor.IssueScrumProcessor;
+import com.publicissapient.kpidashboard.rally.reader.*;
+import com.publicissapient.kpidashboard.rally.tasklet.*;
+import com.publicissapient.kpidashboard.rally.writer.IssueScrumWriter;
+
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.Step;
+import org.springframework.batch.core.launch.support.RunIdIncrementer;
+import org.springframework.batch.core.repository.JobRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.transaction.PlatformTransactionManager;
+
+@Configuration
+public class RallyProcessorJob {
+
+ @Autowired
+ IssueRqlReader issueRqlReader;
+
+ @Autowired
+ IssueSprintReader issueSprintReader;
+
+ @Autowired
+ IssueScrumProcessor issueScrumProcessor;
+
+ @Autowired
+ IssueScrumWriter issueScrumWriter;
+
+ @Autowired
+ MetaDataTasklet metaDataTasklet;
+
+ @Autowired
+ SprintScrumBoardTasklet sprintScrumBoardTasklet;
+
+ @Autowired
+ JiraIssueReleaseStatusTasklet jiraIssueReleaseStatusTasklet;
+
+ @Autowired
+ SprintReportTasklet sprintReportTasklet;
+
+ @Autowired
+ ScrumReleaseDataTasklet scrumReleaseDataTasklet;
+
+ @Autowired
+ JiraIssueJqlWriterListener jiraIssueJqlWriterListener;
+
+ @Autowired
+ JobListenerScrum jobListenerScrum;
+
+ @Autowired
+ JiraIssueSprintJobListener jiraIssueSprintJobListener;
+
+ @Autowired
+ RallyProcessorConfig rallyProcessorConfig;
+
+ @Autowired
+ JobRepository jobRepository;
+
+ @Autowired
+ PlatformTransactionManager transactionManager;
+
+ @Autowired
+ BuilderFactory builderFactory;
+
+ @Autowired
+ JobStepProgressListener jobStepProgressListener;
+
+ private Step processProjectStatusStep() {
+ return builderFactory.getStepBuilder("Fetch Release Status Scrum", jobRepository)
+ .tasklet(jiraIssueReleaseStatusTasklet, transactionManager).listener(jobStepProgressListener).build();
+ }
+
+ private Step scrumReleaseDataStep() {
+ return builderFactory.getStepBuilder("Fetch Release Data Scrum", jobRepository)
+ .tasklet(scrumReleaseDataTasklet, transactionManager).listener(jobStepProgressListener).build();
+ }
+
+
+ /** Scrum projects for Jql job : Start * */
+ /**
+ * @return Job
+ */
+ @TrackExecutionTime
+ @Bean
+ public Job fetchIssueScrumRqlJob(@Qualifier("fetchIssueSprintJob") Job fetchIssueScrumRqlJob) {
+ return builderFactory.getJobBuilder("FetchIssueScrum RQL Job", jobRepository).incrementer(new RunIdIncrementer())
+ .start(metaDataStep()).next(processProjectStatusStep()).next(fetchIssueScrumRqlChunkStep())
+ .next(scrumReleaseDataStep()).listener(jobListenerScrum).build();
+ }
+
+ @TrackExecutionTime
+ private Step fetchIssueScrumRqlChunkStep() {
+ return builderFactory.getStepBuilder("Fetch Issues Scrum Rql", jobRepository)
+ .chunk(getChunkSize(), this.transactionManager).reader(issueRqlReader)
+ .processor(issueScrumProcessor).writer(issueScrumWriter).listener(jiraIssueJqlWriterListener).build();
+ }
+
+ /**
+ * This method is setup job for fetching sprint details based on sprint id
+ *
+ * @return job
+ */
+ @TrackExecutionTime
+ @Bean
+ public Job fetchIssueSprintJob() {
+ return builderFactory.getJobBuilder("fetchIssueSprint Job", jobRepository).incrementer(new RunIdIncrementer())
+ .start(sprintDataStep()).next(fetchIssueSprintChunkStep()).listener(jiraIssueSprintJobListener).build();
+ }
+
+ /**
+ * This method is setup job for fetching sprint details based on sprint id
+ *
+ * @return job
+ */
+ @TrackExecutionTime
+ @Bean
+ public Job runMetaDataStep() {
+ return builderFactory
+ .getJobBuilder("runMetaDataStep Job", jobRepository).incrementer(new RunIdIncrementer()).start(builderFactory
+ .getStepBuilder("Fetch Metadata", jobRepository).tasklet(metaDataTasklet, transactionManager).build())
+ .build();
+ }
+
+ private Step sprintDataStep() {
+ return builderFactory.getStepBuilder("Fetch Sprint Data", jobRepository)
+ .tasklet(sprintReportTasklet, transactionManager).build();
+ }
+
+ @TrackExecutionTime
+ private Step fetchIssueSprintChunkStep() {
+ return builderFactory.getStepBuilder("Fetch Issue-Sprint", jobRepository)
+ .chunk(getChunkSize(), this.transactionManager).reader(issueSprintReader)
+ .processor(issueScrumProcessor).writer(issueScrumWriter).build();
+ }
+
+ private Integer getChunkSize() {
+ return rallyProcessorConfig.getChunkSize();
+ }
+
+ private Step metaDataStep() {
+ return builderFactory.getStepBuilder("Fetch Metadata", jobRepository).tasklet(metaDataTasklet, transactionManager)
+ .listener(jobStepProgressListener).build();
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JiraIssueJqlWriterListener.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JiraIssueJqlWriterListener.java
new file mode 100644
index 000000000..a87f8012f
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JiraIssueJqlWriterListener.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+package com.publicissapient.kpidashboard.rally.listener;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import com.publicissapient.kpidashboard.rally.config.RallyProcessorConfig;
+import com.publicissapient.kpidashboard.rally.constant.RallyConstants;
+import com.publicissapient.kpidashboard.rally.model.CompositeResult;
+import com.publicissapient.kpidashboard.rally.util.JiraProcessorUtil;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.batch.core.ItemWriteListener;
+import org.springframework.batch.core.scope.context.StepContext;
+import org.springframework.batch.core.scope.context.StepSynchronizationManager;
+import org.springframework.batch.item.Chunk;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.publicissapient.kpidashboard.common.constant.ProcessorConstants;
+import com.publicissapient.kpidashboard.common.model.ProcessorExecutionTraceLog;
+import com.publicissapient.kpidashboard.common.model.jira.JiraIssue;
+import com.publicissapient.kpidashboard.common.repository.tracelog.ProcessorExecutionTraceLogRepository;
+import com.publicissapient.kpidashboard.common.util.DateUtil;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author pankumar8
+ */
+@Component
+@Slf4j
+public class JiraIssueJqlWriterListener implements ItemWriteListener {
+ @Autowired
+ private ProcessorExecutionTraceLogRepository processorExecutionTraceLogRepo;
+ @Autowired
+ private RallyProcessorConfig rallyProcessorConfig;
+
+ @Override
+ public void beforeWrite(Chunk extends CompositeResult> compositeResult) {
+ // in future we can use this method to do something before saving data in db
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.springframework.batch.core.ItemWriteListener#afterWrite(java.util.List)
+ */
+ @Override
+ public void afterWrite(Chunk extends CompositeResult> compositeResults) {
+ log.info("Saving status in Processor execution Trace log for Scrum Jql project");
+
+ List processorExecutionToSave = new ArrayList<>();
+ List jiraIssues = compositeResults.getItems().stream().map(CompositeResult::getJiraIssue).toList();
+
+ Map> projectWiseIssues = jiraIssues.stream()
+ .collect(Collectors.groupingBy(JiraIssue::getBasicProjectConfigId));
+ // getting step context
+ StepContext stepContext = StepSynchronizationManager.getContext();
+ for (Map.Entry> entry : projectWiseIssues.entrySet()) {
+ processProject(entry, stepContext, processorExecutionToSave);
+ }
+ if (CollectionUtils.isNotEmpty(processorExecutionToSave)) {
+ processorExecutionTraceLogRepo.saveAll(processorExecutionToSave);
+ }
+ }
+
+ private void processProject(Map.Entry> entry, StepContext stepContext,
+ List processorExecutionToSave) {
+ String basicProjectConfigId = entry.getKey();
+ List procTraceLogList = processorExecutionTraceLogRepo
+ .findByProcessorNameAndBasicProjectConfigIdIn(ProcessorConstants.JIRA,
+ Collections.singletonList(basicProjectConfigId));
+ ProcessorExecutionTraceLog progressStatsTraceLog = procTraceLogList.stream()
+ .filter(ProcessorExecutionTraceLog::isProgressStats).findFirst().orElse(new ProcessorExecutionTraceLog());
+ JiraIssue firstIssue = entry.getValue().stream()
+ .sorted(Comparator.comparing((JiraIssue jiraIssue) -> LocalDateTime.parse(jiraIssue.getChangeDate(),
+ DateTimeFormatter.ofPattern(RallyConstants.JIRA_ISSUE_CHANGE_DATE_FORMAT))).reversed())
+ .findFirst().orElse(null);
+ if (firstIssue != null) {
+ processTraceLogs(stepContext, processorExecutionToSave, procTraceLogList, basicProjectConfigId, firstIssue,
+ progressStatsTraceLog);
+ }
+ }
+
+ private void processTraceLogs(StepContext stepContext, List processorExecutionToSave,
+ List procTraceLogList, String basicProjectConfigId, JiraIssue firstIssue,
+ ProcessorExecutionTraceLog progressStatsTraceLog) {
+ boolean isAnyLastSuccessfulRunPresent = procTraceLogList.stream()
+ .anyMatch(traceLog -> traceLog.getLastSuccessfulRun() != null && !traceLog.getLastSuccessfulRun().isEmpty());
+ if (CollectionUtils.isNotEmpty(procTraceLogList) && isAnyLastSuccessfulRunPresent) {
+ for (ProcessorExecutionTraceLog processorExecutionTraceLog : procTraceLogList) {
+ if (processorExecutionTraceLog.isProgressStats()) {
+ JiraProcessorUtil.saveChunkProgressInTrace(processorExecutionTraceLog, stepContext);
+ }
+ setTraceLog(processorExecutionTraceLog, basicProjectConfigId, firstIssue.getChangeDate(),
+ processorExecutionToSave);
+ }
+ } else {
+ ProcessorExecutionTraceLog processorExecutionTraceLog = new ProcessorExecutionTraceLog();
+ processorExecutionTraceLog.setFirstRunDate(
+ DateUtil.dateTimeFormatter(LocalDateTime.now().minusMonths(rallyProcessorConfig.getPrevMonthCountToFetchData())
+ .minusDays(rallyProcessorConfig.getDaysToReduce()), RallyConstants.QUERYDATEFORMAT));
+ setTraceLog(processorExecutionTraceLog, basicProjectConfigId, firstIssue.getChangeDate(),
+ processorExecutionToSave);
+ progressStatsTraceLog.setLastSuccessfulRun(DateUtil.dateTimeConverter(firstIssue.getChangeDate(),
+ RallyConstants.JIRA_ISSUE_CHANGE_DATE_FORMAT, DateUtil.DATE_TIME_FORMAT));
+ Optional.ofNullable(JiraProcessorUtil.saveChunkProgressInTrace(progressStatsTraceLog, stepContext))
+ .ifPresent(processorExecutionToSave::add);
+ }
+ }
+
+ private void setTraceLog(ProcessorExecutionTraceLog processorExecutionTraceLog, String basicProjectConfigId,
+ String changeDate, List processorExecutionToSave) {
+ processorExecutionTraceLog.setBasicProjectConfigId(basicProjectConfigId);
+ processorExecutionTraceLog.setLastSuccessfulRun(
+ DateUtil.dateTimeConverter(changeDate, RallyConstants.JIRA_ISSUE_CHANGE_DATE_FORMAT, DateUtil.DATE_TIME_FORMAT));
+ processorExecutionTraceLog.setProcessorName(RallyConstants.RALLY);
+ processorExecutionToSave.add(processorExecutionTraceLog);
+ }
+
+ @Override
+ public void onWriteError(Exception exception, Chunk extends CompositeResult> compositeResult) {
+ log.error("Exception occured while writing jira Issue for Scrum jql project ", exception);
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JiraIssueSprintJobListener.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JiraIssueSprintJobListener.java
new file mode 100644
index 000000000..13dee4c28
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JiraIssueSprintJobListener.java
@@ -0,0 +1,95 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+package com.publicissapient.kpidashboard.rally.listener;
+
+import java.io.IOException;
+
+import com.publicissapient.kpidashboard.rally.cache.RallyProcessorCacheEvictor;
+import org.springframework.batch.core.BatchStatus;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.JobExecutionListener;
+import org.springframework.batch.core.configuration.annotation.JobScope;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import com.publicissapient.kpidashboard.common.constant.CommonConstant;
+import com.publicissapient.kpidashboard.common.model.application.SprintTraceLog;
+import com.publicissapient.kpidashboard.common.repository.application.SprintTraceLogRepository;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Component
+@Slf4j
+@JobScope
+public class JiraIssueSprintJobListener implements JobExecutionListener {
+
+ @Autowired
+ SprintTraceLogRepository sprintTraceLogRepository;
+
+ @Autowired
+ RallyProcessorCacheEvictor processorCacheEvictor;
+
+ @Value("#{jobParameters['sprintId']}")
+ private String sprintId;
+
+ @Override
+ public void beforeJob(JobExecution jobExecution) {
+ // in future we can use this method to do something before saving data in db
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.springframework.batch.core.listener.JobExecutionListenerSupport#afterJob(
+ * org.springframework.batch.core.JobExecution)
+ */
+ @Override
+ public void afterJob(JobExecution jobExecution) {
+ log.info("****** Creating Sprint trace log ********");
+ long endTime = System.currentTimeMillis();
+ // saving the execution details
+
+ SprintTraceLog sprintTrace = sprintTraceLogRepository.findFirstBySprintId(sprintId);
+ sprintTrace.setLastSyncDateTime(endTime);
+ if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
+ sprintTrace.setErrorInFetch(false);
+ sprintTrace.setFetchSuccessful(true);
+ // clearing cache
+ processorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT, CommonConstant.JIRA_KPI_CACHE);
+ processorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT, CommonConstant.CACHE_PROJECT_TOOL_CONFIG);
+ processorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT, CommonConstant.CACHE_PROJECT_KPI_DATA);
+
+ } else {
+ sprintTrace.setErrorInFetch(true);
+ sprintTrace.setFetchSuccessful(false);
+ }
+ log.info("Saving sprint Trace Log for sprintId: {}", sprintId);
+ sprintTraceLogRepository.save(sprintTrace);
+// if (jiraClientService.isContainRestClient(sprintId)) {
+// try {
+// jiraClientService.getRestClientMap(sprintId).close();
+// } catch (IOException e) {
+// throw new RuntimeException("Failed to close rest client", e); // NOSONAR
+// }
+// jiraClientService.removeRestClientMapClientForKey(sprintId);
+// jiraClientService.removeKerberosClientMapClientForKey(sprintId);
+// }
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JobListenerKanban.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JobListenerKanban.java
new file mode 100644
index 000000000..a4ebea9d7
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JobListenerKanban.java
@@ -0,0 +1,232 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+package com.publicissapient.kpidashboard.rally.listener;
+
+import static com.publicissapient.kpidashboard.rally.helper.RallyHelper.convertDateToCustomFormat;
+import static com.publicissapient.kpidashboard.rally.util.JiraProcessorUtil.generateLogMessage;
+
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import com.publicissapient.kpidashboard.rally.cache.RallyProcessorCacheEvictor;
+import com.publicissapient.kpidashboard.rally.config.FetchProjectConfiguration;
+import com.publicissapient.kpidashboard.rally.config.RallyProcessorConfig;
+import com.publicissapient.kpidashboard.rally.constant.RallyConstants;
+import com.publicissapient.kpidashboard.rally.model.ProjectConfFieldMapping;
+import com.publicissapient.kpidashboard.rally.service.JiraClientService;
+import com.publicissapient.kpidashboard.rally.service.RallyCommonService;
+import com.publicissapient.kpidashboard.rally.service.NotificationHandler;
+import com.publicissapient.kpidashboard.rally.service.OngoingExecutionsService;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.batch.core.BatchStatus;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.JobExecutionListener;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.batch.core.configuration.annotation.JobScope;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import com.publicissapient.kpidashboard.common.constant.CommonConstant;
+import com.publicissapient.kpidashboard.common.model.ProcessorExecutionTraceLog;
+import com.publicissapient.kpidashboard.common.model.application.FieldMapping;
+import com.publicissapient.kpidashboard.common.model.application.ProjectBasicConfig;
+import com.publicissapient.kpidashboard.common.repository.application.FieldMappingRepository;
+import com.publicissapient.kpidashboard.common.repository.application.ProjectBasicConfigRepository;
+import com.publicissapient.kpidashboard.common.repository.jira.KanbanJiraIssueRepository;
+import com.publicissapient.kpidashboard.common.repository.tracelog.ProcessorExecutionTraceLogRepository;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author purgupta2
+ */
+@Component
+@Slf4j
+@JobScope
+public class JobListenerKanban implements JobExecutionListener {
+
+ @Autowired
+ private NotificationHandler handler;
+
+ @Value("#{jobParameters['projectId']}")
+ private String projectId;
+
+ @Autowired
+ private FieldMappingRepository fieldMappingRepository;
+
+ @Autowired
+ private ProcessorExecutionTraceLogRepository processorExecutionTraceLogRepo;
+
+ @Autowired
+ private RallyProcessorCacheEvictor rallyProcessorCacheEvictor;
+
+ @Autowired
+ private OngoingExecutionsService ongoingExecutionsService;
+
+ @Autowired
+ private RallyProcessorConfig rallyProcessorConfig;
+
+ @Autowired
+ private ProjectBasicConfigRepository projectBasicConfigRepo;
+
+ @Autowired
+ private RallyCommonService rallyCommonService;
+
+ @Autowired
+ JiraClientService jiraClientService;
+
+ @Autowired
+ KanbanJiraIssueRepository kanbanJiraIssueRepository;
+
+ @Autowired
+ FetchProjectConfiguration fetchProjectConfiguration;
+
+ @Override
+ public void beforeJob(JobExecution jobExecution) {
+ // in future we can use this method to do something before job execution starts
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.springframework.batch.core.listener.JobExecutionListenerSupport#afterJob(
+ * org.springframework.batch.core.JobExecution)
+ */
+ @Override
+ public void afterJob(JobExecution jobExecution) {
+ log.info("********In kanban JobExecution listener - finishing job ********");
+ rallyProcessorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT,
+ CommonConstant.CACHE_ACCOUNT_HIERARCHY_KANBAN);
+ rallyProcessorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT,
+ CommonConstant.CACHE_ORGANIZATION_HIERARCHY);
+ rallyProcessorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT, CommonConstant.CACHE_PROJECT_TOOL_CONFIG);
+ rallyProcessorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT, CommonConstant.CACHE_PROJECT_HIERARCHY);
+ rallyProcessorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT, CommonConstant.JIRAKANBAN_KPI_CACHE);
+ try {
+ // sending notification in case of job failure
+ if (jobExecution.getStatus() == BatchStatus.FAILED) {
+ log.error("job failed : {} for the project : {}", jobExecution.getJobInstance().getJobName(), projectId);
+ Throwable stepFaliureException = null;
+ for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
+ if (stepExecution.getStatus() == BatchStatus.FAILED) {
+ stepFaliureException = stepExecution.getFailureExceptions().get(0);
+ break;
+ }
+ }
+ setExecutionInfoInTraceLog(false, stepFaliureException);
+ sendNotification(stepFaliureException);
+ } else {
+ setExecutionInfoInTraceLog(true, null);
+ }
+ } catch (Exception e) {
+ log.error("An Exception has occured in kanban jobListener", e);
+ } finally {
+ log.info("removing project with basicProjectConfigId {}", projectId);
+ // Mark the execution as completed
+ ongoingExecutionsService.markExecutionAsCompleted(projectId);
+// if (jiraClientService.isContainRestClient(projectId)) {
+// try {
+// jiraClientService.getRestClientMap(projectId).close();
+// } catch (IOException e) {
+// throw new RuntimeException("Failed to close rest client", e); // NOSONAR
+// }
+// jiraClientService.removeRestClientMapClientForKey(projectId);
+// jiraClientService.removeKerberosClientMapClientForKey(projectId);
+// }
+ }
+ }
+
+ private void sendNotification(Throwable stepFaliureException) throws UnknownHostException {
+ FieldMapping fieldMapping = fieldMappingRepository.findByProjectConfigId(projectId);
+ ProjectBasicConfig projectBasicConfig = projectBasicConfigRepo.findByStringId(projectId).orElse(null);
+ if (fieldMapping == null || (fieldMapping.getNotificationEnabler() && projectBasicConfig != null)) {
+ handler.sendEmailToProjectAdminAndSuperAdmin(
+ convertDateToCustomFormat(System.currentTimeMillis()) + " on " + rallyCommonService.getApiHost() + " for \"" +
+ getProjectName(projectBasicConfig) + "\"",
+ generateLogMessage(stepFaliureException), projectId, RallyConstants.ERROR_NOTIFICATION_SUBJECT_KEY,
+ RallyConstants.ERROR_MAIL_TEMPLATE_KEY);
+ } else {
+ log.info("Notification Switch is Off for the project : {}. So No mail is sent to project admin", projectId);
+ }
+ }
+
+ private static String getProjectName(ProjectBasicConfig projectBasicConfig) {
+ return projectBasicConfig == null ? "" : projectBasicConfig.getProjectName();
+ }
+
+ private void setExecutionInfoInTraceLog(boolean status, Throwable stepFailureException) {
+ List procExecTraceLogs = processorExecutionTraceLogRepo
+ .findByProcessorNameAndBasicProjectConfigIdIn(RallyConstants.RALLY, Collections.singletonList(projectId));
+ if (CollectionUtils.isNotEmpty(procExecTraceLogs)) {
+ for (ProcessorExecutionTraceLog processorExecutionTraceLog : procExecTraceLogs) {
+ checkDeltaIssues(processorExecutionTraceLog, status);
+ processorExecutionTraceLog.setExecutionEndedAt(System.currentTimeMillis());
+ processorExecutionTraceLog.setExecutionSuccess(status);
+ if (stepFailureException != null && processorExecutionTraceLog.isProgressStats()) {
+ processorExecutionTraceLog.setErrorMessage(generateLogMessage(stepFailureException));
+ processorExecutionTraceLog.setFailureLog(stepFailureException.getMessage());
+ }
+ }
+ processorExecutionTraceLogRepo.saveAll(procExecTraceLogs);
+ }
+ }
+
+ private void checkDeltaIssues(ProcessorExecutionTraceLog processorExecutionTraceLog, boolean status) {
+ try {
+ if (StringUtils.isNotEmpty(processorExecutionTraceLog.getFirstRunDate()) && status) {
+ if (StringUtils.isNotEmpty(processorExecutionTraceLog.getBoardId())) {
+ String query = "updatedDate>='" + processorExecutionTraceLog.getFirstRunDate() + "' ";
+// Promise promisedRs = jiraClientService.getRestClientMap(projectId).getCustomIssueClient()
+// .searchBoardIssue(processorExecutionTraceLog.getBoardId(), query, 0, 0, RallyConstants.ISSUE_FIELD_SET);
+// SearchResult searchResult = promisedRs.claim();
+// if (searchResult != null && (searchResult.getTotal() != kanbanJiraIssueRepository
+// .countByBasicProjectConfigIdAndExcludeTypeName(projectId, RallyConstants.EPIC))) {
+// processorExecutionTraceLog.setDataMismatch(true);
+// }
+ } else {
+ ProjectConfFieldMapping projectConfig = fetchProjectConfiguration.fetchConfiguration(projectId);
+ String issueTypes = Arrays.stream(projectConfig.getFieldMapping().getJiraIssueTypeNames())
+ .map(array -> "\"" + String.join("\", \"", array) + "\"").collect(Collectors.joining(", "));
+ StringBuilder query = new StringBuilder("project in (")
+ .append(projectConfig.getProjectToolConfig().getProjectKey()).append(") and ");
+
+ String userQuery = projectConfig.getJira().getBoardQuery().toLowerCase().split(RallyConstants.ORDERBY)[0];
+ query.append(userQuery);
+ query.append(" and issuetype in (").append(issueTypes).append(" ) and updatedDate>='")
+ .append(processorExecutionTraceLog.getFirstRunDate()).append("' ");
+ log.info("jql query :{}", query);
+// Promise promisedRs = jiraClientService.getRestClientMap(projectId).getProcessorSearchClient()
+// .searchJql(query.toString(), 0, 0, RallyConstants.ISSUE_FIELD_SET);
+// SearchResult searchResult = promisedRs.claim();
+// if (searchResult != null && (searchResult.getTotal() != kanbanJiraIssueRepository
+// .countByBasicProjectConfigIdAndExcludeTypeName(projectId, CommonConstant.BLANK))) {
+// processorExecutionTraceLog.setDataMismatch(true);
+// }
+ }
+ }
+ } catch (Exception e) {
+ log.error("Some error occured while calculating dataMistch", e);
+ }
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JobListenerScrum.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JobListenerScrum.java
new file mode 100644
index 000000000..604ef1269
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JobListenerScrum.java
@@ -0,0 +1,269 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+package com.publicissapient.kpidashboard.rally.listener;
+
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.bson.types.ObjectId;
+import org.springframework.batch.core.BatchStatus;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.JobExecutionListener;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.batch.core.configuration.annotation.JobScope;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import com.publicissapient.kpidashboard.common.constant.CommonConstant;
+import com.publicissapient.kpidashboard.common.model.ProcessorExecutionTraceLog;
+import com.publicissapient.kpidashboard.common.model.application.FieldMapping;
+import com.publicissapient.kpidashboard.common.model.application.IterationData;
+import com.publicissapient.kpidashboard.common.model.application.ProjectBasicConfig;
+import com.publicissapient.kpidashboard.common.repository.application.FieldMappingRepository;
+import com.publicissapient.kpidashboard.common.repository.application.ProjectBasicConfigRepository;
+import com.publicissapient.kpidashboard.common.repository.tracelog.ProcessorExecutionTraceLogRepository;
+import com.publicissapient.kpidashboard.rally.cache.RallyProcessorCacheEvictor;
+import com.publicissapient.kpidashboard.rally.config.FetchProjectConfiguration;
+import com.publicissapient.kpidashboard.rally.config.RallyProcessorConfig;
+import com.publicissapient.kpidashboard.rally.constant.RallyConstants;
+import com.publicissapient.kpidashboard.rally.model.ProjectConfFieldMapping;
+import com.publicissapient.kpidashboard.rally.service.NotificationHandler;
+import com.publicissapient.kpidashboard.rally.service.OngoingExecutionsService;
+import com.publicissapient.kpidashboard.rally.service.OutlierSprintStrategy;
+import com.publicissapient.kpidashboard.rally.service.ProjectHierarchySyncService;
+import com.publicissapient.kpidashboard.rally.service.RallyCommonService;
+
+import lombok.extern.slf4j.Slf4j;
+
+import static com.publicissapient.kpidashboard.rally.helper.RallyHelper.convertDateToCustomFormat;
+import static com.publicissapient.kpidashboard.rally.util.JiraProcessorUtil.generateLogMessage;
+
+/**
+ * @author pankumar8
+ */
+@Component
+@Slf4j
+@JobScope
+public class JobListenerScrum implements JobExecutionListener {
+
+ @Autowired
+ private NotificationHandler handler;
+
+ @Value("#{jobParameters['projectId']}")
+ private String projectId;
+
+ @Autowired
+ private FieldMappingRepository fieldMappingRepository;
+
+ @Autowired
+ private ProcessorExecutionTraceLogRepository processorExecutionTraceLogRepo;
+
+ @Autowired
+ private RallyProcessorCacheEvictor rallyProcessorCacheEvictor;
+
+ @Autowired
+ private OngoingExecutionsService ongoingExecutionsService;
+
+ @Autowired
+ private RallyProcessorConfig rallyProcessorConfig;
+
+ @Autowired
+ private ProjectBasicConfigRepository projectBasicConfigRepo;
+
+ @Autowired
+ private RallyCommonService rallyCommonService;
+
+ @Autowired
+ FetchProjectConfiguration fetchProjectConfiguration;
+
+ @Autowired
+ private ProjectHierarchySyncService projectHierarchySyncService;
+
+ @Autowired
+ private OutlierSprintStrategy outlierSprintStrategy;
+
+ @Override
+ public void beforeJob(JobExecution jobExecution) {
+ // in future we can use this method to do something before job execution starts
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.springframework.batch.core.listener.JobExecutionListenerSupport#afterJob(
+ * org.springframework.batch.core.JobExecution)
+ */
+ @Override
+ public void afterJob(JobExecution jobExecution) {
+ log.info("********in scrum JobExecution listener - finishing job *********");
+ // Sync the sprint hierarchy
+ projectHierarchySyncService.syncScrumSprintHierarchy(new ObjectId(projectId));
+ Map> projOutlierSprintMap = outlierSprintStrategy.execute(new ObjectId(projectId));
+ rallyProcessorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT, CommonConstant.CACHE_ACCOUNT_HIERARCHY);
+ rallyProcessorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT,
+ CommonConstant.CACHE_ORGANIZATION_HIERARCHY);
+ rallyProcessorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT, CommonConstant.CACHE_SPRINT_HIERARCHY);
+ rallyProcessorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT, CommonConstant.CACHE_PROJECT_HIERARCHY);
+ rallyProcessorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT, CommonConstant.CACHE_PROJECT_TOOL_CONFIG);
+ rallyProcessorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_ENDPOINT, CommonConstant.JIRA_KPI_CACHE);
+ rallyProcessorCacheEvictor.evictCache(CommonConstant.CACHE_CLEAR_PROJECT_SOURCE_ENDPOINT, projectId,
+ CommonConstant.JIRA_KPI);
+ try {
+ if (jobExecution.getStatus() == BatchStatus.FAILED) {
+ log.error("job failed : {} for the project : {}", jobExecution.getJobInstance().getJobName(), projectId);
+ Throwable stepFaliureException = null;
+ for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
+ if (stepExecution.getStatus() == BatchStatus.FAILED) {
+ stepFaliureException = stepExecution.getFailureExceptions().get(0);
+ break;
+ }
+ }
+ setExecutionInfoInTraceLog(false, stepFaliureException, projOutlierSprintMap);
+ final String failureReasonMsg = generateLogMessage(stepFaliureException);
+ sendNotification(failureReasonMsg, RallyConstants.ERROR_NOTIFICATION_SUBJECT_KEY,
+ RallyConstants.ERROR_MAIL_TEMPLATE_KEY);
+ }
+// else {
+// setExecutionInfoInTraceLog(true, null, projOutlierSprintMap);
+// }
+ } catch (Exception e) {
+ log.error("An Exception has occured in scrum jobListener", e);
+ } finally {
+ log.info("removing project with basicProjectConfigId {}", projectId);
+ // Mark the execution as completed
+ ongoingExecutionsService.markExecutionAsCompleted(projectId);
+ log.info("removing client for basicProjectConfigId {}", projectId);
+// if (jiraClientService.isContainRestClient(projectId)) {
+// try {
+// jiraClientService.getRestClientMap(projectId).close();
+// } catch (IOException e) {
+// throw new RuntimeException("Failed to close rest client", e); // NOSONAR
+// }
+// jiraClientService.removeRestClientMapClientForKey(projectId);
+// jiraClientService.removeKerberosClientMapClientForKey(projectId);
+// }
+ }
+ }
+
+ private void sendNotification(String notificationMessage, String notificationSubjectKey, String mailTemplateKey)
+ throws UnknownHostException {
+ FieldMapping fieldMapping = fieldMappingRepository.findByProjectConfigId(projectId);
+ ProjectBasicConfig projectBasicConfig = projectBasicConfigRepo.findByStringId(projectId).orElse(null);
+ if (fieldMapping == null || (fieldMapping.getNotificationEnabler() && projectBasicConfig != null)) {
+ handler.sendEmailToProjectAdminAndSuperAdmin(
+ convertDateToCustomFormat(System.currentTimeMillis()) + " on " + rallyCommonService.getApiHost() + " for \"" +
+ getProjectName(projectBasicConfig) + "\"",
+ notificationMessage, projectId, notificationSubjectKey, mailTemplateKey);
+ } else {
+ log.info("Notification Switch is Off for the project : {}. So No mail is sent to project admin", projectId);
+ }
+ }
+
+ private static String getProjectName(ProjectBasicConfig projectBasicConfig) {
+ return projectBasicConfig == null ? "" : projectBasicConfig.getProjectName();
+ }
+
+ private void setExecutionInfoInTraceLog(boolean status, Throwable stepFailureException,
+ Map> outlierSprintMap) {
+ List procExecTraceLogs = processorExecutionTraceLogRepo
+ .findByProcessorNameAndBasicProjectConfigIdIn(RallyConstants.RALLY, Collections.singletonList(projectId));
+ if (CollectionUtils.isNotEmpty(procExecTraceLogs)) {
+ for (ProcessorExecutionTraceLog processorExecutionTraceLog : procExecTraceLogs) {
+ checkDeltaIssues(processorExecutionTraceLog, status);
+ processorExecutionTraceLog.setExecutionEndedAt(System.currentTimeMillis());
+ processorExecutionTraceLog.setExecutionSuccess(status);
+ if (stepFailureException != null && processorExecutionTraceLog.isProgressStats()) {
+ processorExecutionTraceLog.setErrorMessage(generateLogMessage(stepFailureException));
+ processorExecutionTraceLog.setFailureLog(stepFailureException.getMessage());
+ }
+ if (MapUtils.isNotEmpty(outlierSprintMap) && processorExecutionTraceLog.isProgressStats()) {
+ // saving outlier sprints details in trace log
+ processorExecutionTraceLog.setAdditionalInfo(outlierSprintMap.entrySet().stream()
+ .map(entry -> new IterationData(entry.getKey(), entry.getValue())).collect(Collectors.toList()));
+ // sending mail
+ String outlierSprintIssuesTable = outlierSprintStrategy.printSprintIssuesTable(outlierSprintMap);
+ try {
+ sendNotification(outlierSprintIssuesTable, RallyConstants.OUTLIER_NOTIFICATION_SUBJECT_KEY,
+ RallyConstants.OUTLIER_MAIL_TEMPLATE_KEY);
+ } catch (UnknownHostException e) {
+ log.error("Exception occurred while sending outlier notification: ", e);
+ }
+ }
+ }
+ processorExecutionTraceLogRepo.saveAll(procExecTraceLogs);
+ }
+ }
+
+ private void checkDeltaIssues(ProcessorExecutionTraceLog processorExecutionTraceLog, boolean status) {
+ try {
+ if (StringUtils.isNotEmpty(processorExecutionTraceLog.getFirstRunDate()) && status) {
+ if (StringUtils.isNotEmpty(processorExecutionTraceLog.getBoardId())) {
+ String issueTypes = Arrays.stream(
+ fetchProjectConfiguration.fetchConfiguration(projectId).getFieldMapping().getJiraIssueTypeNames())
+ .map(array -> "\"" + String.join("\", \"", array) + "\"").collect(Collectors.joining(", "));
+ StringBuilder query = new StringBuilder("project in (")
+ .append(fetchProjectConfiguration.fetchConfiguration(projectId).getProjectToolConfig().getProjectKey())
+ .append(") and ");
+ String userQuery = fetchProjectConfiguration.fetchConfiguration(projectId).getJira().getBoardQuery()
+ .toLowerCase().split(RallyConstants.ORDERBY)[0];
+ query.append(userQuery);
+ query.append(" and issuetype in (").append(issueTypes).append(" ) and updatedDate>='")
+ .append(processorExecutionTraceLog.getFirstRunDate()).append("' ");
+ log.info("jql query :{}", query);
+// Promise promisedRs = jiraClientService.getRestClientMap(projectId).getProcessorSearchClient()
+// .searchJql(query.toString(), 0, 0, RallyConstants.ISSUE_FIELD_SET);
+// SearchResult searchResult = promisedRs.claim();
+// if (searchResult != null && (searchResult.getTotal() != jiraIssueRepository
+// .countByBasicProjectConfigIdAndExcludeTypeName(projectId, CommonConstant.BLANK))) {
+// processorExecutionTraceLog.setDataMismatch(true);
+// }
+ } else {
+ ProjectConfFieldMapping projectConfig = fetchProjectConfiguration.fetchConfiguration(projectId);
+ String issueTypes = Arrays.stream(projectConfig.getFieldMapping().getJiraIssueTypeNames())
+ .map(array -> "\"" + String.join("\", \"", array) + "\"").collect(Collectors.joining(", "));
+ StringBuilder query = new StringBuilder("project in (")
+ .append(projectConfig.getProjectToolConfig().getProjectKey()).append(") and ");
+
+ String userQuery = projectConfig.getJira().getBoardQuery().toLowerCase().split(RallyConstants.ORDERBY)[0];
+ query.append(userQuery);
+ query.append(" and issuetype in (").append(issueTypes).append(" ) and updatedDate>='")
+ .append(processorExecutionTraceLog.getFirstRunDate()).append("' ");
+ log.info("jql query :{}", query);
+// Promise promisedRs = jiraClientService.getRestClientMap(projectId).getProcessorSearchClient()
+// .searchJql(query.toString(), 0, 0, RallyConstants.ISSUE_FIELD_SET);
+// SearchResult searchResult = promisedRs.claim();
+// if (searchResult != null && (searchResult.getTotal() != jiraIssueRepository
+// .countByBasicProjectConfigIdAndExcludeTypeName(projectId, CommonConstant.BLANK))) {
+// processorExecutionTraceLog.setDataMismatch(true);
+// }
+ }
+ }
+ } catch (Exception e) {
+ log.error("Some error occured while calculating dataMistch", e);
+ }
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JobStepProgressListener.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JobStepProgressListener.java
new file mode 100644
index 000000000..4c22ade61
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/listener/JobStepProgressListener.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.publicissapient.kpidashboard.rally.listener;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+import com.publicissapient.kpidashboard.rally.constant.RallyConstants;
+import org.springframework.batch.core.BatchStatus;
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.batch.core.StepExecutionListener;
+import org.springframework.batch.core.configuration.annotation.StepScope;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import com.publicissapient.kpidashboard.common.constant.ProcessorConstants;
+import com.publicissapient.kpidashboard.common.model.ProcessorExecutionTraceLog;
+import com.publicissapient.kpidashboard.common.model.application.ProgressStatus;
+import com.publicissapient.kpidashboard.common.repository.tracelog.ProcessorExecutionTraceLogRepository;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author shunaray
+ */
+@Component
+@Slf4j
+@StepScope
+public class JobStepProgressListener implements StepExecutionListener {
+
+ @Autowired
+ ProcessorExecutionTraceLogRepository processorExecutionTraceLogRepository;
+
+ @Value("#{jobParameters['projectId']}")
+ private String projectId;
+
+ /**
+ * (non-Javadoc)
+ *
+ * @param stepExecution
+ * instance of {@link StepExecution}.
+ */
+ @Override
+ public void beforeStep(StepExecution stepExecution) {
+ // in the future, we can use this method to do something before saving data in
+ // db
+ }
+
+ /**
+ * (non-Javadoc)
+ *
+ * @param stepExecution
+ * instance of {@link StepExecution}.
+ * @return null
+ */
+ @Override
+ public ExitStatus afterStep(StepExecution stepExecution) {
+ String stepName = stepExecution.getStepName();
+ BatchStatus status = stepExecution.getStatus();
+ ProgressStatus progressStatus = new ProgressStatus();
+ progressStatus.setStepName(stepName);
+ progressStatus.setStatus(status.toString());
+ progressStatus.setEndTime(System.currentTimeMillis());
+ log.info("Step {} done with status {}", stepName, status);
+ saveProgressStatusInTraceLog(RallyConstants.RALLY, projectId, progressStatus);
+ return null;
+ }
+
+ /**
+ * Save the progress status of a processor in the trace log
+ *
+ * @param processorName
+ * projectId
+ * @param basicProjectConfigId
+ * Name of the processor
+ * @param progressStatus
+ * Progress status of the processor
+ */
+ public void saveProgressStatusInTraceLog(String processorName, String basicProjectConfigId,
+ ProgressStatus progressStatus) {
+ Optional existingTraceLog = processorExecutionTraceLogRepository
+ .findByProcessorNameAndBasicProjectConfigIdAndProgressStatsTrue(processorName, basicProjectConfigId);
+ ProcessorExecutionTraceLog processorExecutionTraceLog = existingTraceLog.orElseGet(ProcessorExecutionTraceLog::new);
+
+ processorExecutionTraceLog.setBasicProjectConfigId(basicProjectConfigId);
+ processorExecutionTraceLog.setProcessorName(processorName);
+ processorExecutionTraceLog.setProgressStats(true);
+ List progressStatusList = Optional.ofNullable(processorExecutionTraceLog.getProgressStatusList())
+ .orElseGet(ArrayList::new);
+ progressStatusList.add(progressStatus);
+ processorExecutionTraceLog.setExecutionOngoing(true);
+ processorExecutionTraceLog.setProgressStatusList(progressStatusList);
+ log.info("Saving the progress of {} processor of step {} for projectId {} ", ProcessorConstants.JIRA,
+ progressStatus.getStepName(), basicProjectConfigId);
+ processorExecutionTraceLogRepository.save(processorExecutionTraceLog);
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/CompositeResult.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/CompositeResult.java
new file mode 100644
index 000000000..a7fa13355
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/CompositeResult.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import java.util.Set;
+
+import com.publicissapient.kpidashboard.common.model.application.ProjectHierarchy;
+import com.publicissapient.kpidashboard.common.model.jira.AssigneeDetails;
+import com.publicissapient.kpidashboard.common.model.jira.JiraIssue;
+import com.publicissapient.kpidashboard.common.model.jira.JiraIssueCustomHistory;
+import com.publicissapient.kpidashboard.common.model.jira.KanbanIssueCustomHistory;
+import com.publicissapient.kpidashboard.common.model.jira.KanbanJiraIssue;
+import com.publicissapient.kpidashboard.common.model.jira.SprintDetails;
+
+import lombok.Data;
+
+@Data
+public class CompositeResult {
+
+ private JiraIssue jiraIssue;
+ private JiraIssueCustomHistory jiraIssueCustomHistory;
+ private Set projectHierarchies;
+ private Set sprintDetailsSet;
+ private AssigneeDetails assigneeDetails;
+ private KanbanJiraIssue kanbanJiraIssue;
+ private KanbanIssueCustomHistory kanbanIssueCustomHistory;
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Defect.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Defect.java
new file mode 100644
index 000000000..8f5b0024b
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Defect.java
@@ -0,0 +1,42 @@
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class Defect {
+ @JsonProperty("FormattedID")
+ private String formattedID;
+ @JsonProperty("Name")
+ private String name;
+ private String requirementRef; // Linked HierarchicalRequirement
+ @JsonProperty("_ref")
+ private String ref;
+ @JsonProperty("_refObjectName")
+ private String refObjectName;
+ @JsonProperty("Owner")
+ private Owner owner;
+ @JsonProperty("ScheduleState")
+ private String scheduleState;
+ @JsonProperty("PlanEstimate")
+ private Double planEstimate;
+ @JsonProperty("_type")
+ private String type;
+ @JsonProperty("Iteration")
+ private Iteration iteration;
+ @JsonProperty("Project")
+ private Project project;
+ @JsonProperty("CreationDate")
+ private String creationDate;
+ @JsonProperty("LastUpdateDate")
+ private String lastUpdateDate;
+ @JsonProperty("ObjectID")
+ private String objectID;
+ @JsonProperty("Requirement")
+ private HierarchicalRequirement requirement; // Link to the hierarchical requirement
+ // Add a field to store linked hierarchical requirements
+ private List linkedRequirements;
+
+}
\ No newline at end of file
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/HierarchicalRequirement.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/HierarchicalRequirement.java
new file mode 100644
index 000000000..f0ede0b20
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/HierarchicalRequirement.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+ public class HierarchicalRequirement {
+ @JsonProperty("_ref")
+ private String ref;
+ @JsonProperty("_refObjectName")
+ private String refObjectName;
+ @JsonProperty("FormattedID")
+ private String formattedID;
+ @JsonProperty("Name")
+ private String name;
+ @JsonProperty("Owner")
+ private Owner owner;
+ @JsonProperty("ScheduleState")
+ private String scheduleState;
+ @JsonProperty("Blocked")
+ private boolean blocked;
+ @JsonProperty("PlanEstimate")
+ private Double planEstimate;
+ @JsonProperty("_type")
+ private String type;
+ @JsonProperty("Iteration")
+ private Iteration iteration;
+ @JsonProperty("Project")
+ private Project project;
+ @JsonProperty("CreationDate")
+ private String creationDate;
+ @JsonProperty("LastUpdateDate")
+ private String lastUpdateDate;
+ @JsonProperty("ObjectID")
+ private String objectID;
+ private String currentIteration;
+ private List pastIterations; // Track spillover
+ // Add a field to store linked defects
+ }
\ No newline at end of file
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Iteration.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Iteration.java
new file mode 100644
index 000000000..a6093f28a
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Iteration.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+ public class Iteration {
+ @JsonProperty("_ref")
+ private String ref;
+ @JsonProperty("_refObjectName")
+ private String refObjectName;
+ @JsonProperty("Name")
+ private String name;
+ @JsonProperty("PlanEstimate")
+ private Double planEstimate;
+ @JsonProperty("StartDate")
+ private String startDate;
+ @JsonProperty("EndDate")
+ private String endDate;
+ @JsonProperty("State")
+ private String state;
+ @JsonProperty("PlannedVelocity")
+ private Double plannedVelocity;
+ @JsonProperty("Workspace")
+ private Workspace workspace;
+ @JsonProperty("Project")
+ private Project project;
+ @JsonProperty("RevisionHistory")
+ private RevisionHistory revisionHistory;
+ @JsonProperty("UserIterationCapacities")
+ private UserIterationCapacity userIterationCapacities;
+ @JsonProperty("WorkProducts")
+ private WorkProducts workProducts;
+ @JsonProperty("LastUpdateDate")
+ private String lastUpdateDate;
+ @JsonProperty("TaskActualTotal")
+ private String taskActualTotal;
+ @JsonProperty("TaskEstimateTotal")
+ private String taskEstimateTotal;
+ @JsonProperty("TaskRemainingTotal")
+ private String taskRemainingTotal;
+ @JsonProperty("ObjectID")
+ private String objectID;
+
+ }
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/IterationResponse.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/IterationResponse.java
new file mode 100644
index 000000000..1d5d2bdba
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/IterationResponse.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class IterationResponse {
+ @JsonProperty("Iteration")
+ private Iteration iteration;
+
+ public Iteration getIteration() {
+ return iteration;
+ }
+
+ public void setIteration(Iteration iteration) {
+ this.iteration = iteration;
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/JiraInfo.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/JiraInfo.java
new file mode 100644
index 000000000..e5031d542
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/JiraInfo.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import lombok.Builder;
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+@Data
+@Builder
+public class JiraInfo {
+ private String username;
+ private String password;
+ private String jiraConfigBaseUrl;
+ private String jiraConfigProxyUrl;
+ private String jiraConfigProxyPort;
+ private String jiraConfigAccessToken;
+ private boolean bearerToken;
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/JiraIssueMetadata.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/JiraIssueMetadata.java
new file mode 100644
index 000000000..67eef2134
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/JiraIssueMetadata.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import java.util.Map;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class JiraIssueMetadata {
+ private Map statusMap;
+ private Map priorityMap;
+ private Map issueTypeMap;
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Owner.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Owner.java
new file mode 100644
index 000000000..a733cac0c
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Owner.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class Owner {
+ @JsonProperty("_rallyAPIMajor")
+ private String _rallyAPIMajor;
+ @JsonProperty("_rallyAPIMinor")
+ private String _rallyAPIMinor;
+ @JsonProperty("_ref")
+ private String _ref;
+ @JsonProperty("_refObjectUUID")
+ private String _refObjectUUID;
+ @JsonProperty("_objectVersion")
+ private String _objectVersion;
+ @JsonProperty("_refObjectName")
+ private String _refObjectName;
+ @JsonProperty("_type")
+ private String _type;
+}
\ No newline at end of file
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Project.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Project.java
new file mode 100644
index 000000000..82e8b8f4c
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Project.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class Project {
+ @JsonProperty("_ref")
+ private String ref;
+ @JsonProperty("_refObjectName")
+ private String projectName;
+ @JsonProperty("CreationDate")
+ private String creationDate;
+ @JsonProperty("ObjectID")
+ private String objectID;
+}
\ No newline at end of file
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/ProjectConfFieldMapping.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/ProjectConfFieldMapping.java
new file mode 100644
index 000000000..fcaf1284c
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/ProjectConfFieldMapping.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model; // NOPMD
+
+import org.bson.types.ObjectId;
+
+import com.publicissapient.kpidashboard.common.model.application.FieldMapping;
+import com.publicissapient.kpidashboard.common.model.application.ProjectBasicConfig;
+import com.publicissapient.kpidashboard.common.model.application.ProjectToolConfig;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ProjectConfFieldMapping {
+ // jira and fields mapping of jira
+ private RallyToolConfig jira;
+ private FieldMapping fieldMapping;
+
+ private ObjectId basicProjectConfigId;
+ // if project is kanban or Scrum
+ private boolean isKanban;
+ private int issueCount;
+ private int sprintCount;
+
+ // For filters basic conf
+ private String projectName;
+ private ProjectToolConfig projectToolConfig;
+ private ObjectId jiraToolConfigId;
+
+ private ProjectBasicConfig projectBasicConfig;
+
+ private JiraIssueMetadata jiraIssueMetadata;
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/QueryResult.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/QueryResult.java
new file mode 100644
index 000000000..66c1f4847
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/QueryResult.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class QueryResult {
+ @JsonProperty("TotalResultCount")
+ private int totalResultCount;
+ @JsonProperty("StartIndex")
+ private int startIndex;
+ @JsonProperty("PageSize")
+ private int pageSize;
+ @JsonProperty("Results")
+ private List results;
+}
\ No newline at end of file
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyAllowedValuesResponse.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyAllowedValuesResponse.java
new file mode 100644
index 000000000..2dad53d62
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyAllowedValuesResponse.java
@@ -0,0 +1,70 @@
+package com.publicissapient.kpidashboard.rally.model;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class RallyAllowedValuesResponse {
+ @JsonProperty("QueryResult")
+ private QueryResult queryResult;
+
+ @Data
+ public static class QueryResult {
+ @JsonProperty("_rallyAPIMajor")
+ private String rallyAPIMajor;
+ @JsonProperty("_rallyAPIMinor")
+ private String rallyAPIMinor;
+ @JsonProperty("Errors")
+ private List errors;
+ @JsonProperty("Warnings")
+ private List warnings;
+ @JsonProperty("TotalResultCount")
+ private int totalResultCount;
+ @JsonProperty("StartIndex")
+ private int startIndex;
+ @JsonProperty("PageSize")
+ private int pageSize;
+ @JsonProperty("Results")
+ private List results;
+ }
+
+ @Data
+ public static class AllowedValue {
+ @JsonProperty("_ref")
+ private String ref;
+ @JsonProperty("_refObjectUUID")
+ private String refObjectUUID;
+ @JsonProperty("_refObjectName")
+ private String refObjectName;
+ @JsonProperty("_type")
+ private String type;
+ @JsonProperty("StringValue")
+ private String stringValue;
+ @JsonProperty("DisplayName")
+ private String displayName;
+ @JsonProperty("Name")
+ private String name;
+
+ public String getDisplayValue() {
+ if (displayName != null && !displayName.isEmpty()) {
+ return displayName;
+ }
+ if (name != null && !name.isEmpty()) {
+ return name;
+ }
+ return stringValue;
+ }
+
+ public String getStringValue() {
+ if (stringValue != null && !stringValue.isEmpty()) {
+ return stringValue;
+ }
+ if (name != null && !name.isEmpty()) {
+ return name;
+ }
+ return displayName;
+ }
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyArtifact.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyArtifact.java
new file mode 100644
index 000000000..418304d6d
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyArtifact.java
@@ -0,0 +1,20 @@
+package com.publicissapient.kpidashboard.rally.model;
+
+import lombok.Data;
+
+@Data
+public class RallyArtifact {
+ private String id;
+ private String rallyAPIMajor;
+ private String rallyAPIMinor;
+ private String ref;
+ private String refObjectUUID;
+ private String refObjectName;
+ private String type;
+ private Iteration iteration;
+ private Release release;
+ private Defect defect;
+ private HierarchicalRequirement hierarchicalRequirement;
+ private boolean isSpilledOver;
+ private boolean isInBacklog;
+}
\ No newline at end of file
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyChangelogGroup.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyChangelogGroup.java
new file mode 100644
index 000000000..13e45600f
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyChangelogGroup.java
@@ -0,0 +1,29 @@
+package com.publicissapient.kpidashboard.rally.model;
+
+import java.util.List;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class RallyChangelogGroup {
+ @JsonProperty("_rallyAPIMajor")
+ private Integer rallyAPIMajor;
+
+ @JsonProperty("_rallyAPIMinor")
+ private Integer rallyAPIMinor;
+
+ @JsonProperty("Errors")
+ private List errors;
+
+ @JsonProperty("Warnings")
+ private List warnings;
+
+ @JsonProperty("CreationDate")
+ private String created;
+
+ @JsonProperty("Owner")
+ private Owner author;
+
+ @JsonProperty("Results")
+ private List items;
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyIssueField.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyIssueField.java
new file mode 100644
index 000000000..5a5fcf5b4
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyIssueField.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+/**
+ * Represents a field change in a Rally issue.
+ * Handles both standard field changes and reference field changes (_ref URLs).
+ */
+@Data
+public class RallyIssueField {
+ @JsonProperty("_rallyAPIMajor")
+ private Integer rallyAPIMajor;
+
+ @JsonProperty("_rallyAPIMinor")
+ private Integer rallyAPIMinor;
+
+ @JsonProperty("_type")
+ private String type;
+
+ @JsonProperty("Name")
+ private String field;
+
+ @JsonProperty("OldValue")
+ private String fromString;
+
+ @JsonProperty("NewValue")
+ private String toString;
+
+ @JsonProperty("OldValueRef")
+ private String from;
+
+ @JsonProperty("NewValueRef")
+ private String to;
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyProcessor.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyProcessor.java
new file mode 100644
index 000000000..18d928d24
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyProcessor.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.publicissapient.kpidashboard.common.constant.ProcessorConstants;
+import com.publicissapient.kpidashboard.common.constant.ProcessorType;
+import com.publicissapient.kpidashboard.common.model.generic.Processor;
+
+import com.publicissapient.kpidashboard.rally.constant.RallyConstants;
+import lombok.Getter;
+import lombok.Setter;
+
+@Getter
+@Setter
+public class RallyProcessor extends Processor {
+
+ /**
+ * retruns rally processor propotype
+ *
+ * @return RallyProcessor
+ */
+ public static RallyProcessor prototype() {
+ RallyProcessor protoType = new RallyProcessor();
+ protoType.setProcessorName(RallyConstants.RALLY);
+ protoType.setOnline(true);
+ protoType.setActive(true);
+ protoType.setLastSuccess(false);
+ protoType.setUpdatedTime(System.currentTimeMillis());
+ protoType.setProcessorType(ProcessorType.AGILE_TOOL);
+ return protoType;
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyReleaseResponse.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyReleaseResponse.java
new file mode 100644
index 000000000..d72e84a1a
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyReleaseResponse.java
@@ -0,0 +1,64 @@
+package com.publicissapient.kpidashboard.rally.model;
+
+import org.joda.time.DateTime;
+import java.util.List;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class RallyReleaseResponse {
+ @JsonProperty("QueryResult")
+ private QueryResult queryResult;
+
+ @Data
+ public static class QueryResult {
+ @JsonProperty("_rallyAPIMajor")
+ private String rallyAPIMajor;
+ @JsonProperty("_rallyAPIMinor")
+ private String rallyAPIMinor;
+ @JsonProperty("Errors")
+ private List errors;
+ @JsonProperty("Warnings")
+ private List warnings;
+ @JsonProperty("TotalResultCount")
+ private int totalResultCount;
+ @JsonProperty("StartIndex")
+ private int startIndex;
+ @JsonProperty("PageSize")
+ private int pageSize;
+ @JsonProperty("Results")
+ private List results;
+ }
+
+ @Data
+ public static class Release {
+ @JsonProperty("_rallyAPIMajor")
+ private String rallyAPIMajor;
+ @JsonProperty("_rallyAPIMinor")
+ private String rallyAPIMinor;
+ @JsonProperty("_ref")
+ private String ref;
+ @JsonProperty("_refObjectUUID")
+ private String refObjectUUID;
+ @JsonProperty("_refObjectName")
+ private String refObjectName;
+ @JsonProperty("_type")
+ private String type;
+ @JsonProperty("ObjectID")
+ private Long id;
+ @JsonProperty("Name")
+ private String name;
+ @JsonProperty("Description")
+ private String description;
+ @JsonProperty("ReleaseStartDate")
+ private DateTime releaseStartDate;
+ @JsonProperty("ReleaseDate")
+ private DateTime releaseDate;
+ @JsonProperty("State")
+ private String state;
+ @JsonProperty("Project")
+ private String project;
+ @JsonProperty("Released")
+ private Boolean released;
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyResponse.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyResponse.java
new file mode 100644
index 000000000..deb356d4b
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyResponse.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class RallyResponse {
+
+ @JsonProperty("QueryResult")
+ private QueryResult QueryResult;
+}
\ No newline at end of file
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyStateResponse.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyStateResponse.java
new file mode 100644
index 000000000..fc535cb83
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyStateResponse.java
@@ -0,0 +1,73 @@
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.List;
+
+@Data
+public class RallyStateResponse {
+ @JsonProperty("QueryResult")
+ private QueryResult queryResult;
+
+ @Data
+ public static class QueryResult {
+ @JsonProperty("_rallyAPIMajor")
+ private String rallyAPIMajor;
+ @JsonProperty("_rallyAPIMinor")
+ private String rallyAPIMinor;
+ @JsonProperty("Errors")
+ private List errors;
+ @JsonProperty("Warnings")
+ private List warnings;
+ @JsonProperty("TotalResultCount")
+ private int totalResultCount;
+ @JsonProperty("StartIndex")
+ private int startIndex;
+ @JsonProperty("PageSize")
+ private int pageSize;
+ @JsonProperty("Results")
+ private List results;
+ }
+
+ @Data
+ public static class State {
+ @JsonProperty("_rallyAPIMajor")
+ private String rallyAPIMajor;
+ @JsonProperty("_rallyAPIMinor")
+ private String rallyAPIMinor;
+ @JsonProperty("_ref")
+ private String ref;
+ @JsonProperty("_refObjectUUID")
+ private String refObjectUUID;
+ @JsonProperty("_refObjectName")
+ private String refObjectName;
+ @JsonProperty("_type")
+ private String type;
+ @JsonProperty("Name")
+ private String name;
+ @JsonProperty("OrderIndex")
+ private int orderIndex;
+ @JsonProperty("Enabled")
+ private boolean enabled;
+ @JsonProperty("StateCategory")
+ private StateCategory stateCategory;
+ }
+
+ @Data
+ public static class StateCategory {
+ @JsonProperty("_rallyAPIMajor")
+ private String rallyAPIMajor;
+ @JsonProperty("_rallyAPIMinor")
+ private String rallyAPIMinor;
+ @JsonProperty("_ref")
+ private String ref;
+ @JsonProperty("_type")
+ private String type;
+ @JsonProperty("Name")
+ private String name;
+ @JsonProperty("TypeName")
+ private String typeName;
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyToolConfig.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyToolConfig.java
new file mode 100644
index 000000000..249f4453d
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyToolConfig.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import java.util.List;
+import java.util.Optional;
+
+import com.publicissapient.kpidashboard.common.model.application.FieldMapping;
+import com.publicissapient.kpidashboard.common.model.connection.Connection;
+import com.publicissapient.kpidashboard.common.model.jira.BoardDetails;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Data
+@Builder
+@Getter
+@Setter
+@AllArgsConstructor
+@NoArgsConstructor
+public class RallyToolConfig {
+ private String basicProjectConfigId;
+ private Optional connection;
+ private String projectId;
+ private String projectKey;
+ private FieldMapping fieldMapping;
+ private String createdAt;
+ private String updatedAt;
+ private boolean queryEnabled;
+ private String boardQuery;
+ private List boards;
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyTypeDefinitionResponse.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyTypeDefinitionResponse.java
new file mode 100644
index 000000000..1c187d02e
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RallyTypeDefinitionResponse.java
@@ -0,0 +1,48 @@
+package com.publicissapient.kpidashboard.rally.model;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class RallyTypeDefinitionResponse {
+ @JsonProperty("QueryResult")
+ private QueryResult queryResult;
+
+ @Data
+ public static class QueryResult {
+ @JsonProperty("_rallyAPIMajor")
+ private String rallyAPIMajor;
+ @JsonProperty("_rallyAPIMinor")
+ private String rallyAPIMinor;
+ @JsonProperty("Errors")
+ private List errors;
+ @JsonProperty("Warnings")
+ private List warnings;
+ @JsonProperty("TotalResultCount")
+ private int totalResultCount;
+ @JsonProperty("StartIndex")
+ private int startIndex;
+ @JsonProperty("PageSize")
+ private int pageSize;
+ @JsonProperty("Results")
+ private List results;
+ }
+
+ @Data
+ public static class TypeDefinition {
+ @JsonProperty("_rallyAPIMajor")
+ private String rallyAPIMajor;
+ @JsonProperty("_rallyAPIMinor")
+ private String rallyAPIMinor;
+ @JsonProperty("_ref")
+ private String ref;
+ @JsonProperty("_refObjectUUID")
+ private String refObjectUUID;
+ @JsonProperty("_refObjectName")
+ private String refObjectName;
+ @JsonProperty("_type")
+ private String type;
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/ReadData.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/ReadData.java
new file mode 100644
index 000000000..dad47d89a
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/ReadData.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import org.bson.types.ObjectId;
+
+import com.atlassian.jira.rest.client.api.domain.Issue;
+
+import lombok.Data;
+
+@Data
+public class ReadData {
+ private HierarchicalRequirement hierarchicalRequirement;
+ private ProjectConfFieldMapping projectConfFieldMapping;
+ private String boardId;
+ private boolean isSprintFetch;
+ private ObjectId processorId;
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Release.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Release.java
new file mode 100644
index 000000000..3c8da6696
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Release.java
@@ -0,0 +1,104 @@
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class Release {
+ @JsonProperty("_rallyAPIMajor")
+ private String rallyAPIMajor;
+
+ @JsonProperty("_rallyAPIMinor")
+ private String rallyAPIMinor;
+
+ @JsonProperty("_ref")
+ private String ref;
+
+ @JsonProperty("_refObjectUUID")
+ private String refObjectUUID;
+
+ @JsonProperty("_refObjectName")
+ private String refObjectName;
+
+ @JsonProperty("_objectVersion")
+ private String objectVersion;
+
+ @JsonProperty("CreationDate")
+ private String creationDate;
+
+ @JsonProperty("_CreatedAt")
+ private String createdAt;
+
+ @JsonProperty("ObjectID")
+ private Long objectID;
+
+ @JsonProperty("ObjectUUID")
+ private String objectUUID;
+
+ @JsonProperty("VersionId")
+ private String versionId;
+
+ @JsonProperty("Accepted")
+ private Double accepted;
+
+ @JsonProperty("CascadedToChildren")
+ private Boolean cascadedToChildren;
+
+ @JsonProperty("GrossEstimateConversionRatio")
+ private Double grossEstimateConversionRatio;
+
+ @JsonProperty("LastUpdateDate")
+ private String lastUpdateDate;
+
+ @JsonProperty("Name")
+ private String name;
+
+ @JsonProperty("Notes")
+ private String notes;
+
+ @JsonProperty("PlanEstimate")
+ private Double planEstimate;
+
+ @JsonProperty("PlannedVelocity")
+ private Double plannedVelocity;
+
+ @JsonProperty("ReleaseDate")
+ private String releaseDate;
+
+ @JsonProperty("ReleaseStartDate")
+ private String releaseStartDate;
+
+ @JsonProperty("State")
+ private String state;
+
+ @JsonProperty("SyncedWithParent")
+ private Boolean syncedWithParent;
+
+ @JsonProperty("TaskActualTotal")
+ private Double taskActualTotal;
+
+ @JsonProperty("TaskEstimateTotal")
+ private Double taskEstimateTotal;
+
+ @JsonProperty("TaskRemainingTotal")
+ private Double taskRemainingTotal;
+
+ @JsonProperty("Theme")
+ private String theme;
+
+ @JsonProperty("Version")
+ private String version;
+
+ @JsonProperty("WorkProducts")
+ private WorkProducts workProducts;
+
+ @JsonProperty("Errors")
+ private List errors;
+
+ @JsonProperty("Warnings")
+ private List warnings;
+}
\ No newline at end of file
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/ReleaseWrapper.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/ReleaseWrapper.java
new file mode 100644
index 000000000..efe42dc51
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/ReleaseWrapper.java
@@ -0,0 +1,12 @@
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ReleaseWrapper {
+ @JsonProperty("Release")
+ private Release release;
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Requirement.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Requirement.java
new file mode 100644
index 000000000..6605dda08
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Requirement.java
@@ -0,0 +1,17 @@
+// Requirement.java
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class Requirement {
+ @JsonProperty("_ref")
+ private String ref;
+ @JsonProperty("_refObjectName")
+ private String refObjectName;
+ @JsonProperty("FormattedID")
+ private String formattedID;
+ @JsonProperty("Name")
+ private String name;
+}
\ No newline at end of file
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RevisionHistory.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RevisionHistory.java
new file mode 100644
index 000000000..c49fe86bd
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/RevisionHistory.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+class RevisionHistory {
+ @JsonProperty("_ref")
+ private String ref;
+ @JsonProperty("_type")
+ private String type;
+}
\ No newline at end of file
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Sprint.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Sprint.java
new file mode 100644
index 000000000..178d50917
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Sprint.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.atlassian.jira.rest.client.api.IdentifiableEntity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/** An object representing a com.atlassian.greenhopper.service.sprint.Sprint. */
+@Getter
+@Setter
+public class Sprint implements IdentifiableEntity {
+ private Long id;
+ private Long rapidViewId;
+ private String state;
+ private String name;
+ private String startDateStr;
+ private String endDateStr;
+ private String completeDateStr;
+ private int sequence;
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/UserIterationCapacity.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/UserIterationCapacity.java
new file mode 100644
index 000000000..42772320d
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/UserIterationCapacity.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class UserIterationCapacity {
+ @JsonProperty("_ref")
+ private String ref;
+ @JsonProperty("Count")
+ private int count;
+}
\ No newline at end of file
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/WorkProducts.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/WorkProducts.java
new file mode 100644
index 000000000..a239c4931
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/WorkProducts.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class WorkProducts {
+ @JsonProperty("_rallyAPIMajor")
+ private String rallyAPIMajor;
+
+ @JsonProperty("_rallyAPIMinor")
+ private String rallyAPIMinor;
+
+ @JsonProperty("_ref")
+ private String ref;
+
+ @JsonProperty("_type")
+ private String type;
+
+ @JsonProperty("Count")
+ private int count;
+}
\ No newline at end of file
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Workspace.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Workspace.java
new file mode 100644
index 000000000..5ecb93d95
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/model/Workspace.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class Workspace {
+ @JsonProperty("_ref")
+ private String ref;
+ @JsonProperty("_refObjectName")
+ private String refObjectName;
+}
\ No newline at end of file
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/parser/CustomChangelogJsonParser.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/parser/CustomChangelogJsonParser.java
new file mode 100644
index 000000000..05e0b635f
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/parser/CustomChangelogJsonParser.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.parser;
+
+import java.util.Collection;
+
+import com.publicissapient.kpidashboard.rally.util.JsonParseUtil;
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+import org.joda.time.DateTime;
+
+import com.atlassian.jira.rest.client.api.domain.BasicUser;
+import com.atlassian.jira.rest.client.api.domain.ChangelogGroup;
+import com.atlassian.jira.rest.client.api.domain.ChangelogItem;
+import com.atlassian.jira.rest.client.internal.json.ChangelogItemJsonParser;
+import com.atlassian.jira.rest.client.internal.json.ChangelogJsonParser;
+
+public class CustomChangelogJsonParser extends ChangelogJsonParser {
+
+ private final ChangelogItemJsonParser changelogItemJsonParser = new ChangelogItemJsonParser();
+
+ @Override
+ public ChangelogGroup parse(JSONObject json) throws JSONException {
+ final DateTime created = JsonParseUtil.parseDateTime(json, "created");
+ final BasicUser author = json.has("author") ? JsonParseUtil.parseBasicUser(json.getJSONObject("author")) : null;
+ final Collection items = JsonParseUtil.parseJsonArray(json.getJSONArray("items"),
+ changelogItemJsonParser);
+ return new ChangelogGroup(author, created, items);
+ }
+}
diff --git a/rally/src/main/java/com/publicissapient/kpidashboard/rally/parser/CustomIssueJsonParser.java b/rally/src/main/java/com/publicissapient/kpidashboard/rally/parser/CustomIssueJsonParser.java
new file mode 100644
index 000000000..e7c9e9e38
--- /dev/null
+++ b/rally/src/main/java/com/publicissapient/kpidashboard/rally/parser/CustomIssueJsonParser.java
@@ -0,0 +1,384 @@
+/*******************************************************************************
+ * Copyright 2014 CapitalOne, LLC.
+ * Further development Copyright 2022 Sapient Corporation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+package com.publicissapient.kpidashboard.rally.parser;
+
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.AFFECTS_VERSIONS_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.ASSIGNEE_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.ATTACHMENT_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.COMMENT_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.COMPONENTS_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.CREATED_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.DESCRIPTION_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.DUE_DATE_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.FIX_VERSIONS_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.ISSUE_TYPE_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.LABELS_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.LINKS_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.PRIORITY_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.PROJECT_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.REPORTER_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.RESOLUTION_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.STATUS_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.SUBTASKS_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.SUMMARY_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.TIMETRACKING_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.UPDATED_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.VOTES_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.WATCHER_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.WORKLOGS_FIELD;
+import static com.atlassian.jira.rest.client.api.domain.IssueFieldId.WORKLOG_FIELD;
+import static com.atlassian.jira.rest.client.internal.json.JsonParseUtil.getStringKeys;
+import static com.atlassian.jira.rest.client.internal.json.JsonParseUtil.parseOptionalJsonObject;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Nullable;
+import javax.ws.rs.core.UriBuilder;
+
+import org.codehaus.jettison.json.JSONArray;
+import org.codehaus.jettison.json.JSONException;
+import org.codehaus.jettison.json.JSONObject;
+import org.joda.time.DateTime;
+
+import com.atlassian.jira.rest.client.api.domain.Attachment;
+import com.atlassian.jira.rest.client.api.domain.BasicComponent;
+import com.atlassian.jira.rest.client.api.domain.BasicIssue;
+import com.atlassian.jira.rest.client.api.domain.BasicPriority;
+import com.atlassian.jira.rest.client.api.domain.BasicProject;
+import com.atlassian.jira.rest.client.api.domain.BasicVotes;
+import com.atlassian.jira.rest.client.api.domain.BasicWatchers;
+import com.atlassian.jira.rest.client.api.domain.ChangelogGroup;
+import com.atlassian.jira.rest.client.api.domain.Comment;
+import com.atlassian.jira.rest.client.api.domain.Issue;
+import com.atlassian.jira.rest.client.api.domain.IssueField;
+import com.atlassian.jira.rest.client.api.domain.IssueFieldId;
+import com.atlassian.jira.rest.client.api.domain.IssueLink;
+import com.atlassian.jira.rest.client.api.domain.IssueType;
+import com.atlassian.jira.rest.client.api.domain.Operations;
+import com.atlassian.jira.rest.client.api.domain.Resolution;
+import com.atlassian.jira.rest.client.api.domain.Status;
+import com.atlassian.jira.rest.client.api.domain.Subtask;
+import com.atlassian.jira.rest.client.api.domain.TimeTracking;
+import com.atlassian.jira.rest.client.api.domain.User;
+import com.atlassian.jira.rest.client.api.domain.Version;
+import com.atlassian.jira.rest.client.api.domain.Worklog;
+import com.atlassian.jira.rest.client.internal.json.AttachmentJsonParser;
+import com.atlassian.jira.rest.client.internal.json.BasicComponentJsonParser;
+import com.atlassian.jira.rest.client.internal.json.BasicIssueJsonParser;
+import com.atlassian.jira.rest.client.internal.json.BasicPriorityJsonParser;
+import com.atlassian.jira.rest.client.internal.json.BasicProjectJsonParser;
+import com.atlassian.jira.rest.client.internal.json.BasicVotesJsonParser;
+import com.atlassian.jira.rest.client.internal.json.CommentJsonParser;
+import com.atlassian.jira.rest.client.internal.json.IssueLinkJsonParserV5;
+import com.atlassian.jira.rest.client.internal.json.IssueTypeJsonParser;
+import com.atlassian.jira.rest.client.internal.json.JsonObjectParser;
+import com.atlassian.jira.rest.client.internal.json.JsonParseUtil;
+import com.atlassian.jira.rest.client.internal.json.OperationsJsonParser;
+import com.atlassian.jira.rest.client.internal.json.ResolutionJsonParser;
+import com.atlassian.jira.rest.client.internal.json.StatusJsonParser;
+import com.atlassian.jira.rest.client.internal.json.SubtaskJsonParser;
+import com.atlassian.jira.rest.client.internal.json.TimeTrackingJsonParserV5;
+import com.atlassian.jira.rest.client.internal.json.VersionJsonParser;
+import com.atlassian.jira.rest.client.internal.json.WatchersJsonParserBuilder;
+import com.atlassian.jira.rest.client.internal.json.WorklogJsonParserV5;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+public class CustomIssueJsonParser implements JsonObjectParser {
+
+ public static final String SCHEMA_SECTION = "schema";
+ public static final String NAMES_SECTION = "names";
+ private static final String FIELDS = "fields";
+ private static final String VALUE_ATTR = "value";
+ private static Set specialFields = Sets.newHashSet(IssueFieldId.ids());
+ private final BasicIssueJsonParser basicIssueJsonParser = new BasicIssueJsonParser();
+ private final IssueLinkJsonParserV5 issueLinkJsonParserV5 = new IssueLinkJsonParserV5();
+ private final BasicVotesJsonParser votesJsonParser = new BasicVotesJsonParser();
+ private final StatusJsonParser statusJsonParser = new StatusJsonParser();
+ private final JsonObjectParser watchersJsonParser = WatchersJsonParserBuilder
+ .createBasicWatchersParser();
+ private final VersionJsonParser versionJsonParser = new VersionJsonParser();
+ private final BasicComponentJsonParser basicComponentJsonParser = new BasicComponentJsonParser();
+ private final AttachmentJsonParser attachmentJsonParser = new AttachmentJsonParser();
+ private final CommentJsonParser commentJsonParser = new CommentJsonParser();
+ private final IssueTypeJsonParser issueTypeJsonParser = new IssueTypeJsonParser();
+ private final BasicProjectJsonParser projectJsonParser = new BasicProjectJsonParser();
+ private final BasicPriorityJsonParser priorityJsonParser = new BasicPriorityJsonParser();
+ private final ResolutionJsonParser resolutionJsonParser = new ResolutionJsonParser();
+ private final CustomUserJsonParser userJsonParser = new CustomUserJsonParser();
+ private final SubtaskJsonParser subtaskJsonParser = new SubtaskJsonParser();
+ private final CustomChangelogJsonParser changelogJsonParser = new CustomChangelogJsonParser();
+ private final OperationsJsonParser operationsJsonParser = new OperationsJsonParser();
+ private final JsonWeakParserForString jsonWeakParserForString = new JsonWeakParserForString();
+ private final JSONObject providedNames;
+ private final JSONObject providedSchema;
+
+ public CustomIssueJsonParser() {
+ providedNames = null;
+ providedSchema = null;
+ }
+
+ public CustomIssueJsonParser(final JSONObject providedNames, final JSONObject providedSchema) {
+ this.providedNames = providedNames;
+ this.providedSchema = providedSchema;
+ }
+
+ static Iterable parseExpandos(final JSONObject json) throws JSONException {
+ final String expando = json.getString("expand");
+ return Splitter.on(',').split(expando);
+ }
+
+ private Collection parseArray(final JSONObject jsonObject, final JsonWeakParser jsonParser,
+ final String arrayAttribute) throws JSONException {
+
+ final JSONArray valueObject = jsonObject.optJSONArray(arrayAttribute);
+ if (valueObject == null) {
+ return new ArrayList<>();
+ }
+ Collection res = new ArrayList<>(valueObject.length());
+ for (int i = 0; i < valueObject.length(); i++) {
+ res.add(jsonParser.parse(valueObject.get(i)));
+ }
+ return res;
+ }
+
+ private Collection parseOptionalArrayNotNullable(final JSONObject json, final JsonWeakParser jsonParser,
+ final String... path) throws JSONException {
+ Collection res = parseOptionalArray(json, jsonParser, path);
+ return res == null ? Collections.emptyList() : res;
+ }
+
+ @Nullable
+ private Collection parseOptionalArray(final JSONObject json, final JsonWeakParser jsonParser,
+ final String... path) throws JSONException {
+ final JSONArray jsonArray = JsonParseUtil.getNestedOptionalArray(json, path);
+ if (jsonArray == null) {
+ return null;
+ }
+ final Collection res = new ArrayList<>(jsonArray.length());
+ for (int i = 0; i < jsonArray.length(); i++) {
+ res.add(jsonParser.parse(jsonArray.get(i)));
+ }
+ return res;
+ }
+
+ private String getFieldStringValue(final JSONObject json, final String attributeName) throws JSONException {
+ final JSONObject fieldsJson = json.getJSONObject(FIELDS);
+
+ final Object summaryObject = fieldsJson.get(attributeName);
+ if (summaryObject instanceof JSONObject) { // pre RALLY 5.0 way
+ return ((JSONObject) summaryObject).getString(VALUE_ATTR);
+ }
+ if (summaryObject instanceof String) { // RALLY 5.0 way
+ return (String) summaryObject;
+ }
+ throw new JSONException("Cannot parse [" + attributeName + "] from available fields");
+ }
+
+ private JSONObject getFieldUnisex(final JSONObject json, final String attributeName) throws JSONException {
+ final JSONObject fieldsJson = json.getJSONObject(FIELDS);
+ final JSONObject fieldJson = fieldsJson.getJSONObject(attributeName);
+ if (fieldJson.has(VALUE_ATTR)) {
+ return fieldJson.getJSONObject(VALUE_ATTR); // pre 5.0 way
+ } else {
+ return fieldJson; // RALLY 5.0 way
+ }
+ }
+
+ @Nullable
+ private String getOptionalFieldStringUnisex(final JSONObject json, final String attributeName) throws JSONException {
+ final JSONObject fieldsJson = json.getJSONObject(FIELDS);
+ return JsonParseUtil.getOptionalString(fieldsJson, attributeName);
+ }
+
+ private String getFieldStringUnisex(final JSONObject json, final String attributeName) throws JSONException {
+ final JSONObject fieldsJson = json.getJSONObject(FIELDS);
+ final Object fieldJson = fieldsJson.get(attributeName);
+ if (fieldJson instanceof JSONObject) {
+ return ((JSONObject) fieldJson).getString(VALUE_ATTR); // pre 5.0 way
+ }
+ return fieldJson.toString(); // RALLY 5.0 way
+ }
+
+ @Override
+ public Issue parse(final JSONObject issueJson) throws JSONException {
+ final BasicIssue basicIssue = basicIssueJsonParser.parse(issueJson);
+ final Iterable expandos = parseExpandos(issueJson);
+ final JSONObject jsonFields = issueJson.getJSONObject(FIELDS);
+ final JSONObject commentsJson = jsonFields.optJSONObject(COMMENT_FIELD.id);
+ final Collection comments = (commentsJson == null)
+ ? Collections.emptyList()
+ : parseArray(commentsJson, new JsonWeakParserForJsonObject(commentJsonParser), "comments");
+
+ final String summary = getFieldStringValue(issueJson, SUMMARY_FIELD.id);
+ final String description = getOptionalFieldStringUnisex(issueJson, DESCRIPTION_FIELD.id);
+
+ final Collection attachments = parseOptionalArray(issueJson,
+ new JsonWeakParserForJsonObject(attachmentJsonParser), FIELDS, ATTACHMENT_FIELD.id);
+ final Collection fields = parseFields(issueJson);
+
+ final IssueType issueType = issueTypeJsonParser.parse(getFieldUnisex(issueJson, ISSUE_TYPE_FIELD.id));
+ final DateTime creationDate = JsonParseUtil.parseDateTime(getFieldStringUnisex(issueJson, CREATED_FIELD.id));
+ final DateTime updateDate = JsonParseUtil.parseDateTime(getFieldStringUnisex(issueJson, UPDATED_FIELD.id));
+
+ final String dueDateString = getOptionalFieldStringUnisex(issueJson, DUE_DATE_FIELD.id);
+ final DateTime dueDate = dueDateString == null ? null : JsonParseUtil.parseDateTimeOrDate(dueDateString);
+
+ final BasicPriority priority = getOptionalNestedField(issueJson, PRIORITY_FIELD.id, priorityJsonParser);
+ final Resolution resolution = getOptionalNestedField(issueJson, RESOLUTION_FIELD.id, resolutionJsonParser);
+ final User assignee = getOptionalNestedField(issueJson, ASSIGNEE_FIELD.id, userJsonParser);
+ final User reporter = getOptionalNestedField(issueJson, REPORTER_FIELD.id, userJsonParser);
+
+ final BasicProject project = projectJsonParser.parse(getFieldUnisex(issueJson, PROJECT_FIELD.id));
+ final Collection issueLinks;
+ issueLinks = parseOptionalArray(issueJson, new JsonWeakParserForJsonObject(issueLinkJsonParserV5),
+ FIELDS, LINKS_FIELD.id);
+
+ Collection subtasks = parseOptionalArray(issueJson,
+ new JsonWeakParserForJsonObject(subtaskJsonParser), FIELDS, SUBTASKS_FIELD.id);
+
+ final BasicVotes votes = getOptionalNestedField(issueJson, VOTES_FIELD.id, votesJsonParser);
+ final Status status = statusJsonParser.parse(getFieldUnisex(issueJson, STATUS_FIELD.id));
+
+ final Collection fixVersions = parseOptionalArray(issueJson,
+ new JsonWeakParserForJsonObject(versionJsonParser), FIELDS, FIX_VERSIONS_FIELD.id);
+ final Collection affectedVersions = parseOptionalArray(issueJson,
+ new JsonWeakParserForJsonObject(versionJsonParser), FIELDS, AFFECTS_VERSIONS_FIELD.id);
+ final Collection components = parseOptionalArray(issueJson,
+ new JsonWeakParserForJsonObject(basicComponentJsonParser), FIELDS, COMPONENTS_FIELD.id);
+
+ final Collection worklogs;
+ final URI selfUri = basicIssue.getSelf();
+
+ final String transitionsUriString;
+ if (issueJson.has(IssueFieldId.TRANSITIONS_FIELD.id)) {
+ Object transitionsObj = issueJson.get(IssueFieldId.TRANSITIONS_FIELD.id);
+ transitionsUriString = (transitionsObj instanceof String) ? (String) transitionsObj : null;
+ } else {
+ transitionsUriString = getOptionalFieldStringUnisex(issueJson, IssueFieldId.TRANSITIONS_FIELD.id);
+ }
+ final URI transitionsUri = parseTransisionsUri(transitionsUriString, selfUri);
+
+ if (JsonParseUtil.getNestedOptionalObject(issueJson, FIELDS, WORKLOG_FIELD.id) != null) {
+ worklogs = parseOptionalArray(issueJson,
+ new JsonWeakParserForJsonObject(new WorklogJsonParserV5(selfUri)), FIELDS, WORKLOG_FIELD.id,
+ WORKLOGS_FIELD.id);
+ } else {
+ worklogs = Collections.emptyList();
+ }
+
+ final BasicWatchers watchers = getOptionalNestedField(issueJson, WATCHER_FIELD.id, watchersJsonParser);
+ final TimeTracking timeTracking = getOptionalNestedField(issueJson, TIMETRACKING_FIELD.id,
+ new TimeTrackingJsonParserV5());
+
+ final Set labels = Sets
+ .newHashSet(parseOptionalArrayNotNullable(issueJson, jsonWeakParserForString, FIELDS, LABELS_FIELD.id));
+
+ final Collection changelog = parseOptionalArray(issueJson,
+ new JsonWeakParserForJsonObject(changelogJsonParser), "changelog", "histories");
+ final Operations operations = parseOptionalJsonObject(issueJson, "operations", operationsJsonParser);
+
+ return new Issue(summary, selfUri, basicIssue.getKey(), basicIssue.getId(), project, issueType, status, description,
+ priority, resolution, attachments, reporter, assignee, creationDate, updateDate, dueDate, affectedVersions,
+ fixVersions, components, timeTracking, fields, comments, transitionsUri, issueLinks, votes, worklogs, watchers,
+ expandos, subtasks, changelog, operations, labels);
+ }
+
+ private URI parseTransisionsUri(final String transitionsUriString, final URI selfUri) {
+ return transitionsUriString != null
+ ? JsonParseUtil.parseURI(transitionsUriString)
+ : UriBuilder.fromUri(selfUri).path("transitions").queryParam("expand", "transitions.fields").build();
+ }
+
+ @Nullable
+ private T getOptionalNestedField(final JSONObject s, final String fieldId, final JsonObjectParser